How can I use “sizeof” in a preprocessor macro?

2020-01-24 06:58发布

Is there any way to use a sizeof in a preprocessor macro?

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 sizeof in the manner described above.

标签: c gcc
11条回答
我欲成王,谁敢阻挡
2楼-- · 2020-01-24 07:28

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:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits
查看更多
迷人小祖宗
3楼-- · 2020-01-24 07:29

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.

1. C11 way

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

Usage:

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

2. Custom macro

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

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

Usage:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

This article explains in details why it works.

3. MS-specific

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

Usage:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);
查看更多
Root(大扎)
4楼-- · 2020-01-24 07:29

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

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

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

查看更多
成全新的幸福
5楼-- · 2020-01-24 07:32

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.

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.

查看更多
冷血范
6楼-- · 2020-01-24 07:34

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

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

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).

查看更多
时光不老,我们不散
7楼-- · 2020-01-24 07:34

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

查看更多
登录 后发表回答