如何在预处理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); }