2009-11-11 76 views
4

我从Visual Studio中编译错误“致命错误C1017:无效整数常量表达式”时没有编译该错误。我将如何做到这一点?C++在预处理器的sizeof()比较中引发编译错误#if

template <class B> 
A *Create() 
{ 
    #if sizeof(B) > sizeof(A) 
    #error sizeof(B) > sizeof(A)! 
    #endif 
    ... 
} 
+1

什么是NodeB和节点?请提供更多细节。 – Kugel 2009-11-11 19:59:28

+2

Duplicate:http://stackoverflow.com/questions/1612322/why-cant-i-use-sizeof-in-a-preprocessor-condition – 2009-11-11 20:01:36

+0

我同意库格尔,我不知道我明白你在尝试什么要做... – 2009-11-11 20:01:59

回答

16

预处理器不理解sizeof()(或数据类型,或标识符,模板或类定义,它需要理解所有这些东西来实现sizeof)。

你在找什么是一个静态断言(由编译器强制执行,它理解所有这些事情)。我用Boost.StaticAssert此:

template <class B> 
A *Create() 
{ 
    BOOST_STATIC_ASSERT(sizeof(B) <= sizeof(A)); 
    ... 
} 
+1

+1错过了原始问题中的主要问题,并且知道C++ 0x也会提供语言功能static_assert()。一些编译器已经提供了它。 – Klaim 2009-11-11 21:01:05

+0

更好的是:'BOOST_MPL_ASSERT_MSG',在编译器错误输出中提供一条健康的消息对您的用户来说更好! – 2009-11-12 13:48:55

6

sizeof()不能在预处理指令中使用。

+0

预处理器能否运行这样的功能? – 2009-11-11 20:01:18

+0

那么我该怎么做我想要的? – 2009-11-11 20:01:24

+0

sizeof()实际上是一个操作符,它是在编译时确定的,所以我认为它应该在预处理器指令中工作 – 2009-11-11 20:02:25

8

预编译器表达式在编译器开始编译之前计算。 sizeof()仅由编译器评估。

+0

+1好解释 – Patrick 2009-11-11 20:03:02

+0

虽然...... – AnT 2009-11-11 20:07:09

7

你不能用预处理器做到这一点。预处理器指令不能使用sizeof等语言级别的元素进行操作。此外,即使它们可以,它仍然无法工作,因为预处理指令很早就从代码中消除了,它们不能期望作为后来实例化的模板代码的一部分工作(这正是您似乎试图实现)。

正确的方法去了解它是使用某种形式的静态断言

template <class B> 
A *Create() 
{ 
    STATIC_ASSERT(sizeof(B) <= sizeof(A)); 
    ... 
} 

的有静态断言那里的不少实现。做一个搜索,并选择一个最适合你的。

3

这不能与预处理器来完成。预处理器在编译器之前以合格执行 - 因此在评估#if时尚未计算节点B和节点的大小。

您可以使用模板编程技术来完成类似的事情。关于这个问题的一本很好的书是Modern C++ Design: Generic Programming and Design Patterns Applied, by Andrei Alexandrescu

这是创建模板IF语句的example from a web page

从这个例子中,你可以使用:
IF< sizeof(NodeB)<sizeof(Node), non_existing_type, int>::RET i;

这两种声明int类型或non_existing_type类型的变量。如果模板IF条件评估为true,假定不存在的类型符合其名称,则会导致编译器错误。您可以将i重命名为描述性的。

使用这将是“滚动你自己的”静态断言,其中许多已经可用。我建议你在玩完自己的游戏之后使用其中的一种。

6

预处理器的编译器(至少在逻辑上它)之前运行,没有用户定义类型的知识(而不是固有的类型,一定很多知识 - 预处理器的INT规模可能比编译器的目标不同

无论如何,要做你想做的事,你应该使用一个STATIC_ASSERT()。请参阅下面的回答:

随着STATIC_ASSERT()你就可以做到这一点:

template <class B> 
A *Create() 
{ 
    STATIC_ASSERT(sizeof(A) >= sizeof(B)); 
    return 0; 
} 
+0

+1 for STATIC_ASSERT – 2009-11-11 20:06:56

+0

我从'sizeof(B)'表达式中移除了'typename'关键字 - MSVC并不在乎,GCC也不喜欢它。就像我刚开始说的那样,'typename'是必需和禁止的规则会让我头疼。我不介意有人评论为什么不允许在这里(至少根据GCC)。 – 2009-11-11 20:35:01

0

这已经解释过,但允许我详细阐述为什么预处理器无法计算结构的大小。除了要求提供一个简单的预处理器的事实太多外,还有一些编译器标志会影响结构的布局方式。

struct X { short a; long b; };

这种结构可能是6个字节或8个字节长,这取决于编译器是否被告知到32位对齐“b”的字段中,出于性能的原因。预处理器无法获得该信息。

0

如果你有兴趣在编译时断言,这将对于C和C++的工作,这里是一个我开发:

#define CONCAT2(x, y)    x ## y 
#define CONCAT(x, y)    CONCAT2(x, y) 

#define COMPILE_ASSERT(expr, name)  \ 
    struct CONCAT(name, __LINE__) { char CONCAT(name, __LINE__) [ (expr) ? 1 : -1 ]; } 

#define CT_ASSERT(expr) COMPILE_ASSERT(expr, ct_assert_) 

的到它是如何工作的,数组的大小为负(当表达式为false时,这是非法的)。通过进一步将其包装在结构定义中,这不会在运行时创建任何东西。

0

我看到很多人说的sizeof不能在预处理器指令中使用, 但是不能成为整个故事,因为我经常使用下面的宏:

#define STATICARRAYSIZE(a) (sizeof(a)/sizeof(*a)) 

例如:

#include <stdio.h> 

#define STATICARRAYSIZE(a) (sizeof(a)/sizeof(*a)) 

int main(int argc, char*argv[]) 
{ 
     unsigned char chars[] = "hello world!"; 
     double  dubls[] = {1, 2, 3, 4, 5}; 

     printf("chars num bytes: %ld, num elements: %ld.\n" , sizeof(chars), STATICARRAYSIZE(chars)); 
     printf("dubls num bytes: %ld, num elements: %ld.\n" , sizeof(dubls), STATICARRAYSIZE(dubls)); 
} 

产量:

orion$ ./a.out 
chars num bytes: 13, num elements: 13. 
dubls num bytes: 40, num elements: 5. 

然而

我也不能在gcc 4.2.1下的#if语句中获得sizeof()来编译。 例如,这不会编译:

#if (sizeof(int) == 2) 
#error uh oh 
#endif 

任何洞察力将不胜感激。

+0

#define为“(sizeof(a)/ sizeof(* a))”做了“STATICARRAYSIZE”的简单文本替换。例如,在第一个printf语句中,当预处理器完成其工作时,它输出字符串“sizeof(chars)/ sizeof(* chars)”,而不是“13” – DGentry 2012-10-29 22:39:06

0

使用MSVC,此代码编译为我:

const int cPointerSize = sizeof(void*); 
const int cFourBytes = 4;` 

#if (cPointerSize == cFourBytes) 
    ... 

然而,这(应该相同工作)不:

#if (sizeof(void*) == 4) ...

+0

请允许我指出void指针的大小为8在64位系统上,不是4。 – YoYoYonnY 2016-03-03 22:21:28