C语言 条件的时间长度

hm2xizp9  于 12个月前  发布在  其他
关注(0)|答案(9)|浏览(161)

如果一个条件涉及sizeof,我想定义一个宏,如果它是true,什么也不做(但仍然编译)。如果预处理器支持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上进行编译时 * Assert *(如果失败则无法编译),但我没有看到一种方法来扩展这种方法。

wztqucjr

wztqucjr1#

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

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

字符串
如果pred的计算结果为0,就像C语言中的false布尔表达式一样,编译器将抛出一个错误。
未来的更新:从C11开始,您可以只使用

static_assert(expression);


assert.h开始。

ogsagwnx

ogsagwnx2#

假设C99,你可以使用

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

#if UINTPTR_MAX <= UINT_MAX
...

字符串
这意味着sizeof (void *) <= sizeof (intptr_t) <= sizeof (int)在任何正常的C语言实现上。

l7wslrjt

l7wslrjt3#

考虑到其他答案已经解释了为什么sizeof不能与#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

字符串

zc0qhyus

zc0qhyus4#

尽管这个问题被标记为C而不是C++,但你可能会发现知道C++0x定义了一种由编译器而不是预处理器检查的静态Assert机制是很有帮助的。
维基百科的例子尤其相关:

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

字符串

tvokkenx

tvokkenx5#

编辑

没关系,正如Steve Rowe指出的,这些预处理器值也由sizeof设置,所以我们只是兜了一个圈子。
由于sizeof直到编译时才求值,因此需要依赖于其他预处理器值。我是这样做的:

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

字符串

anauzrmj

anauzrmj6#

你在这里混淆了两个编译步骤。当你编译一个C程序时,第一步是预处理器,它解析包括,宏,任何以'#'开头的行。然后是编译,它顺便计算表达式的大小。
这是两个不同的二进制文件,你不能把这种类型的信息从一个传递到另一个。你必须使用系统定义的宏,如__i386__或__x86_64__,如果你想弄清楚你在什么架构上,然后推导int和指针大小。

e5njpo68

e5njpo687#

理解这一点的一种方法是数据模型的概念(例如参见http://sourceforge.net/p/predef/wiki/DataModels/)。
有几种数据模型,包括LP 32 ILP32 LP 64 LLP64 ILP64,在大多数平台上,cc前端命令定义了当前模型(例如_ILP32表示int,long和指针是32位,而_LP 64表示long和指针是64位)。

m1m5dgzv

m1m5dgzv8#

sizeof是一个编译时操作符。#if和#define与预处理器相关。由于预处理器在编译器之前运行,因此这不起作用。然而,您可能会找到一个《双城之战》编译器开关,允许您多遍传递它(即预处理,假装编译,预处理,编译)但是,公平地说,我会给予尝试做你想要的。它不意味着工作,简单地说,它不。
你最好的办法是将这些定义设置为传递给编译器的-D命令。你可以静态地Assert所选择的命令是正确的。这样你只需要在外部为给定的编译模式(例如PowerPC Release)设置一些定义,等等。

cotxawn7

cotxawn79#

正确的解决方案是使用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强加了一个额外的规则,它也必须足够大,可以容纳函数指针)。
如果您随后要打印这些值或原始指针,您可以使用来自<inttypes.h>的信息:

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

相关问题