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 函数来包装它。