我从Visual Studio中编译错误“致命错误C1017:无效整数常量表达式”时没有编译该错误。我将如何做到这一点?C++在预处理器的sizeof()比较中引发编译错误#if
template <class B>
A *Create()
{
#if sizeof(B) > sizeof(A)
#error sizeof(B) > sizeof(A)!
#endif
...
}
我从Visual Studio中编译错误“致命错误C1017:无效整数常量表达式”时没有编译该错误。我将如何做到这一点?C++在预处理器的sizeof()比较中引发编译错误#if
template <class B>
A *Create()
{
#if sizeof(B) > sizeof(A)
#error sizeof(B) > sizeof(A)!
#endif
...
}
预处理器不理解sizeof()(或数据类型,或标识符,模板或类定义,它需要理解所有这些东西来实现sizeof)。
你在找什么是一个静态断言(由编译器强制执行,它理解所有这些事情)。我用Boost.StaticAssert此:
template <class B>
A *Create()
{
BOOST_STATIC_ASSERT(sizeof(B) <= sizeof(A));
...
}
+1错过了原始问题中的主要问题,并且知道C++ 0x也会提供语言功能static_assert()。一些编译器已经提供了它。 – Klaim 2009-11-11 21:01:05
更好的是:'BOOST_MPL_ASSERT_MSG',在编译器错误输出中提供一条健康的消息对您的用户来说更好! – 2009-11-12 13:48:55
sizeof()不能在预处理指令中使用。
预处理器能否运行这样的功能? – 2009-11-11 20:01:18
那么我该怎么做我想要的? – 2009-11-11 20:01:24
sizeof()实际上是一个操作符,它是在编译时确定的,所以我认为它应该在预处理器指令中工作 – 2009-11-11 20:02:25
你不能用预处理器做到这一点。预处理器指令不能使用sizeof
等语言级别的元素进行操作。此外,即使它们可以,它仍然无法工作,因为预处理指令很早就从代码中消除了,它们不能期望作为后来实例化的模板代码的一部分工作(这正是您似乎试图实现)。
正确的方法去了解它是使用某种形式的静态断言
template <class B>
A *Create()
{
STATIC_ASSERT(sizeof(B) <= sizeof(A));
...
}
的有静态断言那里的不少实现。做一个搜索,并选择一个最适合你的。
这不能与预处理器来完成。预处理器在编译器之前以合格执行 - 因此在评估#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
重命名为描述性的。
使用这将是“滚动你自己的”静态断言,其中许多已经可用。我建议你在玩完自己的游戏之后使用其中的一种。
预处理器的编译器(至少在逻辑上它)之前运行,没有用户定义类型的知识(而不是固有的类型,一定很多知识 - 预处理器的INT规模可能比编译器的目标不同
无论如何,要做你想做的事,你应该使用一个STATIC_ASSERT()
。请参阅下面的回答:
随着STATIC_ASSERT()
你就可以做到这一点:
template <class B>
A *Create()
{
STATIC_ASSERT(sizeof(A) >= sizeof(B));
return 0;
}
+1 for STATIC_ASSERT – 2009-11-11 20:06:56
我从'sizeof(B)'表达式中移除了'typename'关键字 - MSVC并不在乎,GCC也不喜欢它。就像我刚开始说的那样,'typename'是必需和禁止的规则会让我头疼。我不介意有人评论为什么不允许在这里(至少根据GCC)。 – 2009-11-11 20:35:01
这已经解释过,但允许我详细阐述为什么预处理器无法计算结构的大小。除了要求提供一个简单的预处理器的事实太多外,还有一些编译器标志会影响结构的布局方式。
struct X { short a; long b; };
这种结构可能是6个字节或8个字节长,这取决于编译器是否被告知到32位对齐“b”的字段中,出于性能的原因。预处理器无法获得该信息。
如果你有兴趣在编译时断言,这将对于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时,这是非法的)。通过进一步将其包装在结构定义中,这不会在运行时创建任何东西。
我看到很多人说的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
任何洞察力将不胜感激。
#define为“(sizeof(a)/ sizeof(* a))”做了“STATICARRAYSIZE”的简单文本替换。例如,在第一个printf语句中,当预处理器完成其工作时,它输出字符串“sizeof(chars)/ sizeof(* chars)”,而不是“13” – DGentry 2012-10-29 22:39:06
使用MSVC,此代码编译为我:
const int cPointerSize = sizeof(void*);
const int cFourBytes = 4;`
#if (cPointerSize == cFourBytes)
...
然而,这(应该相同工作)不:
#if (sizeof(void*) == 4)
...
请允许我指出void指针的大小为8在64位系统上,不是4。 – YoYoYonnY 2016-03-03 22:21:28
什么是NodeB和节点?请提供更多细节。 – Kugel 2009-11-11 19:59:28
Duplicate:http://stackoverflow.com/questions/1612322/why-cant-i-use-sizeof-in-a-preprocessor-condition – 2009-11-11 20:01:36
我同意库格尔,我不知道我明白你在尝试什么要做... – 2009-11-11 20:01:59