如何在预处理macros中使用“sizeof”?
有没有在预处理macros中使用sizeof
?
例如,多年来我一直想做类似的事情,
#if sizeof(someThing) != PAGE_SIZE #error Data structure doesn't match page size #endif
我在这里检查的确切的东西是完全组成的 – 关键是,我经常喜欢把这些types的(大小或alignment)编译时检查,以防止有人修改一个数据结构,可能misalign或re-大小的事情会打破他们。
不用说 – 我似乎没有能够以上述方式使用sizeof
。
有没有在预处理器macros中使用“
sizeof
”?
不需要。条件指令采用一组受限制的条件expression式。 sizeof
是不允许的事情之一。
预处理指令在源文件被parsing之前(至less在概念上)被评估,所以没有任何types或variables可以获得它们的大小。
但是,有一些技巧可以在C中获得编译时断言(例如,参见本页 )。
有几种方法可以做到这一点。 如果sizeof(someThing)
等于PAGE_SIZE
,则以下片段不会产生任何代码; 否则会产生编译时错误。
1. C ++ 11的方法
从C ++ 11开始,你可以使用static_assert
。
用法:
static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");
2.自定义macros
如果你只是想在sizeof(something)
不是你所期望的时候出现编译时错误,你可以使用下面的macros:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
用法:
BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );
这篇文章详细解释了它为什么起作用。
3.特定于MS的
在Microsoft C ++编译器中,您可以使用C_ASSERTmacros(需要#include <windows.h>
),它使用类似于第2节中描述的技巧。
用法:
C_ASSERT(sizeof(someThing) == PAGE_SIZE);
我知道这个线程真的很老,但…
我的解决scheme
extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];
只要expression式等于零,编译就好了。 其他任何东西,它就在那里炸毁。 因为variables是extern'd它将不占用空间,只要没有人引用它(他们不会),它不会导致链接错误。
不像assertmacros那么灵活,但是我不能在我的GCC版本中编译这个,而且我认为它可以在任何地方编译。
下一个macros是什么:
/* * Simple compile time assertion. * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes); */ #define CT_ASSERT(exp, message_identifier) \ struct compile_time_assertion { \ char message_identifier : 8 + !(exp); \ }
例如在评论MSVC告诉类似于:
test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits
我知道这是一个迟到的答案,但要增加迈克的版本,这里是我们使用的版本不分配任何内存。 我没有拿出原始大小的检查,我几年前在互联网上发现它,不幸的是不能参考作者。 另外两个只是同一个想法的延伸。
因为他们是typedef的,没有分配。 在__LINE__这个名字中,它总是一个不同的名字,所以可以在需要时复制和粘贴。 这适用于MS Visual Studio C编译器和GCC Arm编译器。 它在CodeWarrior中不起作用,CW抱怨重新定义,不使用__LINE__预处理器构造。
//Check overall structure size typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1]; //check 8 byte alignment for flash write or similar typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1]; //check offset in structure to ensure a piece didn't move typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];
#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
可能工作
现有的答案只是展示了如何根据types的大小来实现“编译时断言”的效果。 这可能会满足OP在这种情况下的需求,但还有其他一些情况下,您确实需要基于types大小的预处理器条件。 以下是如何做到这一点:
写下自己的一个C程序,如:
/* you could call this sizeof_int.c if you like... */ #include <stdio.h> /* 'int' is just an example, it could be any other type */ int main(void) { printf("%zd", sizeof(int); }
编译一下。 用你最喜欢的脚本语言编写脚本,运行上面的C程序并捕获它的输出。 使用该输出来生成一个C头文件。 例如,如果您使用的是Ruby,则可能如下所示:
sizeof_int = `./sizeof_int` File.open('include/sizes.h','w') { |f| f.write(<<HEADER) } /* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */ #define SIZEOF_INT #{sizeof_int} /* others can go here... */ HEADER
然后将一个规则添加到您的Makefile或其他构build脚本中,这将使其运行上述脚本来构buildsizes.h
。
在需要使用基于大小的预处理器条件的地方包括sizes.h
。
完成!
(你有没有input过./configure && make
来build立一个程序? configure
脚本的function基本上就像上面那样…)
作为本次讨论的参考,我报告说一些编译器会得到sizeof()ar预处理器时间。
JamesMcNellis的答案是正确的,但有些编译器会经历这个限制(这可能违反了严格的ansi c)。
作为一个例子,我指的是IAR C编译器(可能是专业微控制器/embedded式编程的领先者)。
在我的可移植的c + +代码( http://www.starmessagesoftware.com/cpcclibrary/ )想要放在我的一些结构或类的大小的安全警卫。
我没有find预处理器抛出一个错误的方法(不能像sizeof()那样工作),我在这里find了一个解决scheme,导致编译器抛出一个错误。 http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
我不得不适应该代码,以使其在我的编译器(xcode)中抛出一个错误:
static union { char int8_t_incorrect[sizeof( int8_t) == 1 ? 1: -1]; char uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1]; char int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1]; char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1]; char int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1]; char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1]; };
sizeof
运算符不适用于预处理器,但可以将sizeof
传递给编译器,并在运行时检查条件:
#define elem_t double #define compiler_size(x) sizeof(x) elem_t n; if (compiler_size(elem_t) == sizeof(int)) { printf("%d",(int)n); } else { printf("%lf",(double)n); }