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:36

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.

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.

//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];
查看更多
够拽才男人
3楼-- · 2020-01-24 07:36

In my portable c++ code ( http://www.starmessagesoftware.com/cpcclibrary/ ) wanted to put a safe guard on the sizes of some of my structs or classes.

Instead of finding a way for the preprocessor to throw an error ( which cannot work with sizeof() as it is stated here ), I found a solution here that causes the compiler to throw an error. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99

I had to adapt that code to make it throw an error in my compiler (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];
};
查看更多
别忘想泡老子
4楼-- · 2020-01-24 07:38

The sizeof operator is not available for the preprocessor, but you can transfer sizeof to the compiler and check the condition in runtime:

#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);
}
查看更多
老娘就宠你
5楼-- · 2020-01-24 07:45

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:

Write yourself a little C program like:

/* 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:

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.

Include sizes.h wherever you need to use preprocessor conditionals based on sizes.

Done!

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

查看更多
我只想做你的唯一
6楼-- · 2020-01-24 07:55

In C11 _Static_assert keyword is added. It can be used like:

_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")
查看更多
登录 后发表回答