条件编译时大小

发布于 2024-10-06 12:59:12 字数 525 浏览 1 评论 0原文

如果涉及 sizeof 的条件为 true,我想定义一个宏,如果为 false,则不执行任何操作(但仍编译)。如果预处理器支持 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/) 解释了如何进行编译时 assertion on sizeof (如果失败则无法编译),但我没有找到一种方法可以将此方法扩展到我想要的。

I want to define a macro if a condition involving sizeof is true and do nothing (but still compile) if it is false. If the preprocessor supported sizeof, it would look like this:

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

There are some pages (e.g. http://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/) which explain how to make a compile-time assertion on sizeof (and fail to compile if it fails), but I don't see a way to extend this approach to what I want.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

ら栖息 2024-10-13 12:59:12

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

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

You just can't do it. sizeof is a compile time operator. #if and #define and preprocessor related. As the preprocessor runs BEFORE the compiler this just won't work. You may, however, be able to find an arcane compiler switch that will allow you to multi pass it (ie preprocess, pretend compile, preprocess, compile) but, in all fairness, I'd give up trying to do what you want. Its not meant to work and, simply, it doesn't.

Your best best is to set such defines as -D commands passed to the compiler. You can statically assert that the ones chosen are correct. This way you just have to set up a few defines externally for a given compile mode (eg PowerPC Release) and so on.

世界等同你 2024-10-13 12:59:12

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

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

您只需要两者之一,因为 #include 包含来自 #include;但是, 中的许多内容仅与使用 scanf()printf() 格式化 I/O 相关>。

给定假定条件:

#if (sizeof(void*) <= sizeof(unsigned int)) // 这里放什么?
# 定义 POINTER_FITS_INTO_UINT
#endif

您所追求的似乎是:

uintptr_t

这是无符号整数类型,足够大以容纳任何指针(即 C 标准中的任何数据指针;POSIX 强加了一条附加规则,即它也必须足够大以容纳函数指针也是如此)。类型 uintptr_t 中定义。

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

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

The correct solution to your problem is to use the C99 standard headers:

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

You only need one of the two because #include <inttypes.h> includes the material from #include <stdint.h>; however, a lot of the material in <inttypes.h> is only relevant to formatted I/O with scanf() and printf().

Given the putative condition:

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

What you seem to be after is known as:

uintptr_t

That is the unsigned integer type that is big enough to hold any pointer (that is, any data pointer in the C standard; POSIX imposes an additional rule that it must also be big enough to hold function pointers too). The type uintptr_t is defined in <stdint.h>.

If you are subsequently going to be printing such values, or raw pointers, you can use the information from <inttypes.h>:

printf("Pointer = 0x%" PRIXPTR "\n", uintptr_value);
printf("Pointer = 0x%" PRIXPTR "\n", (uintptr_t)any_pointer);
泅渡 2024-10-13 12:59:12

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

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

如果 pred 的计算结果为 0,就像 C 中的 false 布尔表达式一样,编译器将抛出错误。

未来更新:从 C11 开始,您可以仅使用

static_assert(expression);

assert.h 中的内容。

This describes how to fake compile-time assertions in C. The short version is to use switch statements:

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

If pred evaluates to 0, like a false boolean expression does in C, the compiler will throw an error.

Update from the future: since C11, you can just use

static_assert(expression);

from assert.h.

靖瑶 2024-10-13 12:59:12

假设 C99,您可以在 C 语言的任何正常实现上使用

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

#if UINTPTR_MAX <= UINT_MAX
...

这意味着 sizeof (void *) <= sizeof (intptr_t) <= sizeof (int)

Assuming C99, you could use

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

#if UINTPTR_MAX <= UINT_MAX
...

which implies sizeof (void *) <= sizeof (intptr_t) <= sizeof (int) on any sane implementation of the C language.

静谧 2024-10-13 12:59:12

鉴于其他答案已经解释了为什么 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

Given that the other answers already explained why sizeof cannot be used with #if, let me provide a simple solution for your case (surprisingly not yet mentioned). Take a look at

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

It mentions several predefined __SIZEOF_XYZ__ macros that actually can be used in preprocessing phase, i.e. also in #if. Assuming unsigned int and int are of same size, your example can be done like this:

#if __SIZEOF_POINTER__ == __SIZEOF_INT__
#define POINTER_FITS_INTO_UINT
#endif
雪落纷纷 2024-10-13 12:59:12

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

维基百科示例特别相关:

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

Even though the question is tagged C rather than C++, you may find it helpful to know that C++0x defines a mechanism for static assertions which are checked by the compiler, not the preprocessor.

The Wikipedia example is particularly relevant:

static_assert (sizeof(int) <= sizeof(T), "T is not big enough!")
祁梦 2024-10-13 12:59:12

编辑

没关系,正如 Steve Rowe 指出的那样,这些预处理器值也由 sizeof 设置,所以我们回到了原点。

由于 sizeof 在编译时才会计算,因此您需要依赖其他预处理器值。 这是我的做法:

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

Edit

Never mind, as Steve Rowe pointed out, these preprocessor values get set by sizeof as well so we just came full circle.

Since sizeof doesn't evaluate until compile time, you need to rely upon other pre-processor values. Here is how I would do it:

#include <values.h>
#if PTRBITS <= INTBITS
#  define POINTER_FITS_INTO_UINT
#endif
满地尘埃落定 2024-10-13 12:59:12

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

这是两个不同的二进制文件,您无法将这种类型的信息从一个二进制文件传递到另一个二进制文件。如果您想确定您所在的体系结构,然后推断 int 和指针大小,则必须使用系统定义的宏,例如 __i386__ 或 __x86_64__。

You're confusing two compilation steps here. When you compile a C program, first step is the preprocessor which resolves includes, macros, any line starting by '#'.
Then comes the compilation which incidentally evaluates the sizeof expressions.

These are two different binaries and you can't pass that type of information from one to another. You'll have to use system defined macros such as __i386__ or __x86_64__ if you want to figure what architecture you are on and then deduce int and pointer sizes.

各空 2024-10-13 12:59:12

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

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

One way to make sense of this is the concept of Data model (see for example http://sourceforge.net/p/predef/wiki/DataModels/).

There are several data models including LP32 ILP32 LP64 LLP64 ILP64 and on most platforms, the cc frontend command defines the current model (e.g. _ILP32 meaning int, long and pointer are 32bit while _LP64 means long and pointer are 64bit).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文