编译时大小有条件

时间:2010-12-07 07:48:36

标签: c c-preprocessor compile-time

如果涉及sizeof的条件为真,我想定义一个宏,如果它为假,则不执行任何操作(但仍然编译)。如果预处理器支持sizeof,它将如下所示:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

有些页面(例如http://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/)解释了如何在sizeof上进行编译时断言(如果失败则无法编译),但我没有办法将这种方法扩展到我想要的方式。

9 个答案:

答案 0 :(得分:14)

你无法做到。 sizeof是一个编译时运算符。 #if和#define以及预处理器相关。由于预处理器在编译器之前运行,因此不起作用。但是,您可以找到一个神秘的编译器开关,它允许您多次传递它(即预处理,假装编译,预处理,编译),但是,平心而论,我会放弃尝试做你想做的事情。它并不意味着工作,简单地说,它没有。

最好的方法是将这样的定义设置为传递给编译器的-D命令。您可以静态断言所选择的是正确的。这样,您只需在外部为给定的编译模式(例如PowerPC Release)设置一些定义,依此类推。

答案 1 :(得分:9)

问题的正确解决方法是使用C99标准标题:

#include <stdint.h>
#include <inttypes.h>

您只需要其中一个,因为#include <inttypes.h>包含来自#include <stdint.h>的资料;但是,<inttypes.h>中的大量素材仅与scanf()printf()的格式化I / O相关。

鉴于推定条件:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

你似乎追求的是:

uintptr_t

这是无符号整数类型,它足以容纳任何指针(即C标准中的任何数据指针; POSIX强加了一个额外的规则,它也必须足够大以容纳函数指针)。类型uintptr_t<stdint.h>中定义。

如果您随后要打印此类值或原始指针,则可以使用<inttypes.h>中的信息:

printf("Pointer = 0x%" PRIXPTR "\n", uintptr_value);
printf("Pointer = 0x%" PRIXPTR "\n", (uintptr_t)any_pointer);

答案 2 :(得分:7)

This描述了如何在C中伪造编译时断言。简短版本是使用switch语句:

#define COMPILE_TIME_ASSERT(pred)            \  
    switch(0){case 0:case pred:;}

如果pred求值为0,就像C中的假布尔表达式一样,编译器将抛出错误。

答案 3 :(得分:5)

假设C99,您可以使用

#include <limits.h>
#include <stdint.h>

#if UINTPTR_MAX <= UINT_MAX
...

暗示{C}语言的任何理智实现sizeof (void *) <= sizeof (intptr_t) <= sizeof (int)

答案 4 :(得分:4)

即使问题是标记C而不是C ++,您可能会发现知道C ++ 0x定义静态断言的机制很有帮助,静态断言由编译器检查,而不是预处理器。

Wikipedia example特别相关:

static_assert (sizeof(int) <= sizeof(T), "T is not big enough!")

答案 5 :(得分:3)

鉴于其他答案已经解释了为什么sizof无法与#if一起使用,让我为您的案例提供一个简单的解决方案(令人惊讶的是尚未提及)。看看

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros

它提到了几个预定义的__SIZEOF_XYZ__宏,这些宏实际上可用于预处理阶段,即也在#if中。假设unsigned intint大小相同,您的示例可以这样完成:

#if __SIZEOF_POINTER__ == __SIZEOF_INT__
#define POINTER_FITS_INTO_UINT
#endif

答案 6 :(得分:1)

修改

没关系,正如Steve Rowe所指出的那样,这些预处理器值也由sizeof设置,所以我们只是完全循环。

由于sizeof在编译时才进行评估,因此您需要依赖其他预处理器值。 我会这样做:

#include <values.h>
#if PTRBITS <= INTBITS
#  define POINTER_FITS_INTO_UINT
#endif

答案 7 :(得分:0)

你在这里混淆了两个编译步骤。编译C程序时,第一步是预处理器,它解析包含宏,任何以'#'开头的行。 然后编译顺便评估了表达式的大小。

这是两个不同的二进制文件,您无法将这类信息从一个传递到另一个。如果你想要确定你所使用的架构,然后推导出int和指针大小,你将不得不使用系统定义的宏,如__i386__或__x86_64__。

答案 8 :(得分:0)

理解这一点的一种方法是数据模型的概念(例如参见http://sourceforge.net/p/predef/wiki/DataModels/)。

有几种数据模型,包括LP32 ILP32 LP64 LLP64 ILP64,在大多数平台上,cc前端命令定义了当前模型(例如_ILP32表示int,long和指针是32位,而_LP64表示长,指针是64位)。