SPI_IOC_MESSAGE(N) 宏让我适应
SPI_IOC_MESSAGE(N) macro giving me fits
我无法让我正在处理的 SPI 程序正常运行,这似乎是 SPI_IOC_MESSAGE(N) 宏的一些问题。
这是不起作用的示例代码 (ioctl returns EINVAL (22) ):
std::vector<spi_ioc_transfer> tr;
<code that fills tr with 1+ transfers>
// Hand the transmission(s) off to the SPI driver
if (tr.size() > 0)
{
int ret = ioctl(fd, SPI_IOC_MESSAGE(tr.size()), tr.data());
if (ret < 1)
{
int err = errno;
}
}
我现在的测试代码正在创建一个长度为 1 的向量。
如果我明确地将代码更改为:
int ret = ioctl(fd, SPI_IOC_MESSAGE( 1 ), tr.data());
...然后 ioctl(...) 成功,我的位进入管道。
查看 Eclipse 中 SPI_IOC_MESSAGE 宏的扩展,我不明白为什么这不开心。
建议?
我正在从 64 位 Linux VM 交叉编译 Linux/ARM (Beaglebone Black),但我看不到这会影响宏。
编辑:
这是 C 预处理器的两个宏扩展
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((tr.size())*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((tr.size())*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
和文字:
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((1)*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((1)*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
绝对可怕,但我认为 tr.size()
在那里的使用方式并不令人惊讶。
编辑以包含似乎是答案的内容
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#include <linux/spi/spidev.h>
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
将 linux SPI 包含文件包装在 "extern C" 中指示系统将该部分视为普通的旧 C,这似乎让我调用 SPI_IOC_MESSAGE( tr.size() )
或 SPI_IOC_MESSAGE( an_int )
并让正确的事情发生(通过 GDB 逐步验证和信号分析仪验证)。
我怀疑问题可能在于宏汤中埋藏的这个特殊金块:
...sizeof(char[...tr.size()...])...
注意到 Linux 代码完全是 C 代码,C 标准(我这里有 C99 草案 n1256)为 sizeof
运算符声明表达式操作数 未计算,结果是常量,除非操作数的类型是变长数组,在这种情况下计算结果是整数。
然而,C++ 标准(C++11 草案 n3242)似乎没有给出计算操作数的任何条件,只说明结果是一个常量。
因此看起来这可能是 C 和 C++ 不同的角落之一,将一个编译为另一个会导致未定义的行为。在那种情况下,我认为选择要么只是破解你自己的宏版本,要么有一个单独的外部 C 函数来包装它。
我无法让我正在处理的 SPI 程序正常运行,这似乎是 SPI_IOC_MESSAGE(N) 宏的一些问题。
这是不起作用的示例代码 (ioctl returns EINVAL (22) ):
std::vector<spi_ioc_transfer> tr;
<code that fills tr with 1+ transfers>
// Hand the transmission(s) off to the SPI driver
if (tr.size() > 0)
{
int ret = ioctl(fd, SPI_IOC_MESSAGE(tr.size()), tr.data());
if (ret < 1)
{
int err = errno;
}
}
我现在的测试代码正在创建一个长度为 1 的向量。 如果我明确地将代码更改为:
int ret = ioctl(fd, SPI_IOC_MESSAGE( 1 ), tr.data());
...然后 ioctl(...) 成功,我的位进入管道。 查看 Eclipse 中 SPI_IOC_MESSAGE 宏的扩展,我不明白为什么这不开心。
建议?
我正在从 64 位 Linux VM 交叉编译 Linux/ARM (Beaglebone Black),但我看不到这会影响宏。
编辑: 这是 C 预处理器的两个宏扩展
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((tr.size())*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((tr.size())*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
和文字:
int ret = ioctl(fd, (((1U) << (((0 +8)+8)+14)) | ((('k')) << (0 +8)) | (((0)) << 0) | ((((sizeof(char[((((1)*(sizeof (struct spi_ioc_transfer))) < (1 << 14)) ? ((1)*(sizeof (struct spi_ioc_transfer))) : 0)])))) << ((0 +8)+8))), tr.data());
绝对可怕,但我认为 tr.size()
在那里的使用方式并不令人惊讶。
编辑以包含似乎是答案的内容
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#include <linux/spi/spidev.h>
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
将 linux SPI 包含文件包装在 "extern C" 中指示系统将该部分视为普通的旧 C,这似乎让我调用 SPI_IOC_MESSAGE( tr.size() )
或 SPI_IOC_MESSAGE( an_int )
并让正确的事情发生(通过 GDB 逐步验证和信号分析仪验证)。
我怀疑问题可能在于宏汤中埋藏的这个特殊金块:
...sizeof(char[...tr.size()...])...
注意到 Linux 代码完全是 C 代码,C 标准(我这里有 C99 草案 n1256)为 sizeof
运算符声明表达式操作数 未计算,结果是常量,除非操作数的类型是变长数组,在这种情况下计算结果是整数。
然而,C++ 标准(C++11 草案 n3242)似乎没有给出计算操作数的任何条件,只说明结果是一个常量。
因此看起来这可能是 C 和 C++ 不同的角落之一,将一个编译为另一个会导致未定义的行为。在那种情况下,我认为选择要么只是破解你自己的宏版本,要么有一个单独的外部 C 函数来包装它。