C语言 如何在预处理器宏中使用“sizeof”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4079243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:53:12  来源:igfitidea点击:

How can I use "sizeof" in a preprocessor macro?

cgcc

提问by Brad

Is there any way to use a sizeofin a preprocessor macro?

有没有办法sizeof在预处理器宏中使用 a ?

For example, there have been a ton of situations over the years in which I wanted to do something like:

例如,多年来有很多情况我想做如下事情:

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

The exact thing I'm checking here is completely made up - the point is, I often like to put in these types of (size or alignment) compile-time checks to guard against someone modifying a data-structure which could misalign or re-size things which would break them.

我在这里检查的确切内容是完全构成的 - 关键是,我经常喜欢进行这些类型的(大小或对齐)编译时检查,以防止有人修改可能会错位或重新排列的数据结构 -大小会破坏它们的东西。

Needless to say - I don't appear to be able to use a sizeofin the manner described above.

不用说 - 我似乎无法以sizeof上述方式使用 a 。

采纳答案by nevermind

There are several ways of doing this. Following snippets will produce no code if sizeof(someThing)equals PAGE_SIZE; otherwise they will produce a compile-time error.

有几种方法可以做到这一点。如果sizeof(someThing)等于PAGE_SIZE,以下代码段将不产生任何代码;否则它们会产生编译时错误。

1. C11 way

1.C11方式

Starting with C11 you can use static_assert(requires #include <assert.h>).

从 C11 开始,您可以使用static_assert(需要#include <assert.h>)。

Usage:

用法:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2. Custom macro

2. 自定义宏

If you just want to get a compile-time error when sizeof(something)is not what you expect, you can use following macro:

如果您只想在sizeof(something)不符合您预期的情况下获得编译时错误,您可以使用以下宏:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

Usage:

用法:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

This articleexplains in details why it works.

这篇文章详细解释了它的工作原理。

3. MS-specific

3. 特定于 MS

On Microsoft C++ compiler you can use C_ASSERTmacro (requires #include <windows.h>), which uses a trick similar to the one described in section 2.

在 Microsoft C++ 编译器上,您可以使用C_ASSERT宏(需要#include <windows.h>),它使用的技巧类似于第 2 节中描述的技巧。

Usage:

用法:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);

回答by James McNellis

Is there anyway to use a "sizeof" in a pre-processor macro?

无论如何sizeof在预处理器宏中使用“ ”?

No. The conditional directives take a restricted set of conditional expressions; sizeofis one of the things not allowed.

否。条件指令采用一组受限制的条件表达式;sizeof是不允许的事情之一。

Preprocessing directives are evaluated before the source is parsed (at least conceptually), so there aren't any types or variables yet to get their size.

预处理指令在解析源之前进行评估(至少在概念上),因此没有任何类型或变量尚未获得它们的大小。

However, there are techniques to getting compile-time assertions in C (for example, see this page).

但是,有一些技术可以在 C 中获取编译时断言(例如,请参阅此页面)。

回答by Scott

I know this thread is really old but...

我知道这个线程真的很旧但是......

My solution:

我的解决方案:

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

As long as that expression equates to zero, it compiles fine. Anything else and it blows up right there. Because the variable is extern'd it will take up no space, and as long as no-one references it (which they won't) it won't cause a link error.

只要该表达式等于零,它就可以正常编译。其他任何东西,它就在那里爆炸。因为变量是 extern'd 它不会占用空间,只要没有人引用它(他们不会),它就不会导致链接错误。

Not as flexible as the assert macro, but I couldn't get that to compile in my version of GCC and this will... and I think it will compile just about anywhere.

不像 assert 宏那样灵活,但我无法在我的 GCC 版本中编译它,这将......而且我认为它几乎可以在任何地方编译。

回答by Paul

I know it's a late answer, but to add on to Mike's version, here's a version we use that doesn't allocate any memory. I didn't come up with the original size check, I found it on the internet years ago and unfortunately can't reference the author. The other two are just extensions of the same idea.

我知道这是一个迟到的答案,但要添加到 Mike 的版本,这是我们使用的一个不分配任何内存的版本。我没有想出原始尺寸检查,我多年前在互联网上找到它,不幸的是无法参考作者。另外两个只是同一想法的延伸。

Because they are typedef's, nothing is allocated. With the __LINE__ in the name, it's always a different name so it can be copied and pasted where needed. This works in MS Visual Studio C compilers, and GCC Arm compilers. It does not work in CodeWarrior, CW complains about redefinition, not making use of the __LINE__ preprocessor construct.

因为它们是 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];

回答by Alex D

The existing answers just show how to achieve the effect of "compile-time assertions" based on the size of a type. That may meet the OP's needs in this particular case, but there are other cases where you really need a preprocessor conditional based on the size of a type. Here's how to do it:

现有的答案只是展示了如何根据类型的大小实现“编译时断言”的效果。在这种特殊情况下,这可能满足 OP 的需求,但在其他情况下,您确实需要一个基于类型大小的预处理器。这是如何做到的:

Write yourself a little C program like:

为自己编写一个小 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); }

Compile that. Write a script in your favorite scripting language, which runs the above C program and captures its output. Use that output to generate a C header file. For example, if you were using Ruby, it might look like:

编译那个。用您最喜欢的脚本语言编写一个脚本,该脚本运行上述 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

Then add a rule to your Makefile or other build script, which will make it run the above script to build sizes.h.

然后将规则添加到您的 Makefile 或其他构建脚本中,这将使其运行上述脚本以构建sizes.h.

Include sizes.hwherever you need to use preprocessor conditionals based on sizes.

包括sizes.h您需要根据大小使用预处理器条件的任何地方。

Done!

完毕!

(Have you ever typed ./configure && maketo build a program? What configurescripts do is basically just like the above...)

(你有没有打字./configure && make来构建程序?configure脚本所做的基本上就像上面一样......)

回答by Sergio

What about next macro:

下一个宏呢:

/* 
 * 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); \
    }

For example in comment MSVC tells something like:

例如,在评论中 MSVC 讲述了类似的内容:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits

回答by graziano governatori

Just as a reference for this discussion, I report that some compilers get sizeof() ar pre-processor time.

作为本次讨论的参考,我报告一些编译器获得 sizeof() ar 预处理器时间。

JamesMcNellis answer is correct, but some compilers go through this limitation (this probably violates strict ansi c).

JamesMcNellis 的回答是正确的,但有些编译器会遇到这个限制(这可能违反了严格的 ansi c)。

As a case of this, I refer to IAR C-compiler (probably the leading one for professional microcontroller/embedded programming).

作为这种情况,我指的是 IAR C 编译器(可能是专业微控制器/嵌入式编程的领先者)。

回答by graziano governatori

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))might work

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))可能有用

回答by cagatayo

In C11 _Static_assertkeyword is added. It can be used like:

在 C11_Static_assert中添加了关键字。它可以像这样使用:

_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")

回答by Coroos

After trying out the mentioned macro's, this fragment seems to produce the desired result (t.h):

在尝试了上述宏之后,这个片段似乎产生了想要的结果 ( 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);

Running cc -E t.h:

运行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];

Running cc -o t.o t.h:

运行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 isn't the answer to everything after all...

42毕竟不是一切的答案......