SPI_IOC_MESSAGE(N)宏适合我 [英] SPI_IOC_MESSAGE(N) macro giving me fits
问题描述
我无法正常工作的SPI程序无法正常运行,并且SPI_IOC_MESSAGE(N)宏似乎存在一些问题.
I'm having trouble getting a SPI program I'm working on to behave correctly and it seems to be some issue with the SPI_IOC_MESSAGE(N) macro.
这是不起作用的示例代码(ioctl返回EINVAL(22)):
Here's sample code that DOESN'T work (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的向量. 如果我将代码明确更改为:
My test code right now is creating a vector of length 1. If I explicitly change the code to:
int ret = ioctl(fd, SPI_IOC_MESSAGE( 1 ), tr.data());
...然后ioctl(...)成功执行,我的任务掉了下来. 看着Eclipse中SPI_IOC_MESSAGE宏的扩展,我不明白为什么这不满意.
...then ioctl(...) succeeds and my bits go down the pipe. Looking at the expansion of the SPI_IOC_MESSAGE macro in Eclipse, I don't see why this isn't happy.
建议?
我正在从64位Linux VM交叉编译Linux/ARM(Beaglebone Black),但是我看不到这会影响宏.
I'm cross-compiling for Linux/ARM (Beaglebone Black) from a 64-bit Linux VM, but that I can't see that affecting the macro.
这是C预处理程序的两个宏扩展
Here are the two macro expansions out of the C pre-processor
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()
那里如何使用它,我并不感到惊讶.
Absolutely hideous, but I don't see anything surprising in how tr.size()
would be getting used there.
编辑以包含似乎是答案的答案
#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
在"extern C"中包装linux SPI include文件,指示系统将该部分视为普通的旧C,这似乎让我调用SPI_IOC_MESSAGE( tr.size() )
或SPI_IOC_MESSAGE( an_int )
并发生了正确的事情(已验证GDB逐步调试和信号分析器).
Wrapping the linux SPI include file in an "extern C" instructs the system to treat that section as plain old C, and that seems to let me call SPI_IOC_MESSAGE( tr.size() )
or SPI_IOC_MESSAGE( an_int )
and have the correct thing happen (verified with GDB stepthrough and a signal analyzer).
推荐答案
我怀疑问题可能出在宏汤中埋藏的这个特殊的金块中:
I suspect the problem might lie in this particular nugget buried in the macro soup:
...sizeof(char[...tr.size()...])...
注意到Linux代码是唯一的C,C标准(这里有C99草案n1256)对sizeof
运算符指出,表达式操作数是未求值的,结果是一个常数, 除非,操作数的类型是可变长度数组,在这种情况下,将对其求值并且结果是整数.
Noting that Linux code is exclusively C, the C standard (I have C99 draft n1256 here) states for the sizeof
operator that an expression operand is unevaluated, and the result is a constant, unless the type of the operand is a variable-length array, in which case it is evaluated and the result is an integer.
但是,C ++标准(C ++ 11草案n3242)似乎没有给出任何条件来评估操作数,而仅说明结果是常量.
The C++ standard (C++11 draft n3242), however, does not seem to give any condition under which the operand is evaluated, and only states the result is a constant.
因此,这似乎可能是C和C ++不同的角落之一,将它们编译在一起会导致不确定的行为.在那种情况下,我认为选择要么是破解自己的宏版本,要么是使用单独的外部C函数对其进行包装.
Thus it looks like this may be one of the corners where C and C++ differ, and compiling one as the other leads to undefined behaviour. In that case, I think the choice is either just hacking up your own version of the macro, or having a separate external C function that wraps it.
这篇关于SPI_IOC_MESSAGE(N)宏适合我的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!