有什么方法可以sizeof
在预处理器宏中使用吗?
例如,多年来,我想做很多事情,例如:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
我在这里检查的确切内容已完全组成-重点是,我经常喜欢放入这些类型的(大小或对齐)编译时检查,以防止有人修改数据结构而导致对齐或重新对齐的情况。大小会破坏它们的东西。
不用说-我似乎无法以sizeof
上述方式使用。
有什么方法可以sizeof
在预处理器宏中使用吗?
例如,多年来,我想做很多事情,例如:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
我在这里检查的确切内容已完全组成-重点是,我经常喜欢放入这些类型的(大小或对齐)编译时检查,以防止有人修改数据结构而导致对齐或重新对齐的情况。大小会破坏它们的东西。
不用说-我似乎无法以sizeof
上述方式使用。
Answers:
有几种方法可以做到这一点。如果sizeof(someThing)
等于PAGE_SIZE
,后面的代码片段将不产生任何代码;否则会产生编译时错误。
从C11开始,您可以使用static_assert
(需要#include <assert.h>
)。
用法:
static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");
如果您只是想在sizeof(something)
预期之外获得编译时错误,则可以使用以下宏:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
用法:
BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );
本文详细说明了其工作原理。
在Microsoft C ++编译器上,您可以使用C_ASSERT宏(requires #include <windows.h>
),该宏使用与第2节中描述的技巧类似的技巧。
用法:
C_ASSERT(sizeof(someThing) == PAGE_SIZE);
gcc
(在4.8.4版中测试)(Linux)中不起作用。在((void)sizeof(...
与expected identifier or '(' before 'void'
和时出错expected ')' before 'sizeof'
。但是原则上size_t x = (sizeof(...
确实可以按预期工作。您必须以某种方式“使用”结果。为了允许在函数内部或全局范围内多次调用此方法,可以extern char _BUILD_BUG_ON_ [ (sizeof(...) ];
重复使用类似的方法(无副作用,实际上不引用_BUILD_BUG_ON_
任何地方)。
无论如何,
sizeof
在预处理器宏中使用“ ”?
否。条件指令采用一组受限制的条件表达式。sizeof
是不允许的事情之一。
预处理指令在解析源之前(至少在概念上)进行评估,因此尚无任何类型或变量来获取其大小。
但是,有一些技巧可以在C语言中获得编译时断言(例如,请参阅此页面)。
我知道这是一个较晚的答案,但是要添加到Mike的版本中,这是我们使用的不分配任何内存的版本。我没有提出原始的尺寸检查,几年前我在互联网上找到了它,很遗憾无法参考作者。其他两个只是同一概念的扩展。
因为它们是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 STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
我知道这个线程真的很旧,但是...
我的解决方案:
extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];
只要该表达式等于零,它就可以编译。其他什么,它就在那里炸毁。因为变量是extern'd,所以它将不占用空间,并且只要没有人引用它(他们不会),就不会导致链接错误。
不像assert宏那样灵活,但是我无法在我的GCC版本中进行编译,因此可以...而且我认为它将几乎可以在任何地方编译。
现有的答案仅显示了如何基于类型的大小来实现“编译时断言”的效果。在这种特殊情况下,这可能可以满足OP的需求,但是在其他情况下,您确实需要基于类型大小的预处理器。方法如下:
给自己写一个小的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 sizes.h
。
包括sizes.h
在需要使用基于大小的预处理器条件的任何地方。
做完了!
(您是否曾经键入过./configure && make
要构建程序的代码?configure
基本上像上面的脚本一样执行脚本...)
那下一个宏呢:
/*
* 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
#if
预处理指令中使用它。
作为此讨论的参考,我报告说某些编译器会在预处理时间获得sizeof()。
JamesMcNellis的答案是正确的,但是某些编译器会遇到此限制(这可能违反了严格的ansi c)。
在这种情况下,我指的是IAR C编译器(可能是专业微控制器/嵌入式编程的领先者)。
#if (sizeof(int) == 8)
在某些情况下(在某些编译器上)确实有效,这真是太好了。” 回复:“一定是在我的时间之前。”来自丹尼斯·里奇。
#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
可能有用
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
条件内使用它的结果。它没有提供任何好处sizeof(x)
。
在我的便携式C ++代码中(http://www.starmessagesoftware.com/cpcclibrary/)中,我想对某些结构或类的大小进行安全防护。
我没有找到预处理器引发错误的方法(这不能与sizeof()一起使用,如此处所述),而是在这里找到了一种导致编译器引发错误的解决方案。 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];
};
在尝试了上述宏之后,该片段似乎产生了所需的结果(t.h
):
#include <sys/cdefs.h>
#define STATIC_ASSERT(condition) typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(int) == 42);
正在运行cc -E t.h
:
# 1 "t.h"
...
# 2 "t.h" 2
typedef char _static_assert_3[ (sizeof(int) == 4) ? 1 : -1];
typedef char _static_assert_4[ (sizeof(int) == 42) ? 1 : -1];
正在运行cc -o t.o t.h
:
% cc -o t.o t.h
t.h:4:1: error: '_static_assert_4' declared as an array with a negative size
STATIC_ASSERT(sizeof(int) == 42);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.h:2:84: note: expanded from macro 'STATIC_ASSERT'
...typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
^~~~~~~~~~~~~~~~~~~~
1 error generated.
毕竟42并不是一切的答案...
为了在编译时根据其约束检查数据结构的大小,我使用了这个技巧。
#if defined(__GNUC__)
{ char c1[sizeof(x)-MAX_SIZEOF_X-1]; } // brakets limit c1's scope
#else
{ char c1[sizeof(x)-MAX_SIZEOF_X]; }
#endif
如果x的大小大于或等于限制MAX_SIZEOF_X,则gcc将抱怨“数组大小太大”错误。VC ++将发出错误C2148(“数组的总大小不能超过0x7fffffff字节”)或C4266“无法分配常量大小为0的数组”。
这两个定义是必需的,因为gcc允许以这种方式定义零大小的数组(sizeof x-n)。
该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);
}
compiler_size
?您的示例尝试显示什么?