【问题标题】:Error checking through Macro通过宏检查错误
【发布时间】:2012-12-30 02:52:18
【问题描述】:

我想编译如下所述的时间错误检查。但我无法在main() 中找到如何使用它?

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
int main(){
BUILD_BUG_ON_NULL(12);
}

下面是提到的错误

1--error C2332: 'struct' : missing tag name
2--error C2143: syntax error : missing ')' before '{'
3--error C2027: use of undefined type 'main::<unnamed-tag>'
4--error C2143: syntax error : missing ';' before '{'
5--error C2059: syntax error : ')'

谁能告诉我我做错了什么?

【问题讨论】:

  • 位域的宽度必须是整数常量表达式。 val 不是一个。所以这行不通。
  • 使用gcc-4.2编译时,报错bitfield.c:5: error: bit-field ‘&lt;anonymous&gt;’ width not an integer constant
  • @DanielFischer:: 我用常量值编辑了问题。但它仍然显示相同的错误。
  • @Learner 这是一个 C 宏,你不应该在 C++ 编译器中使用它。
  • 如果你解释你想要做什么,你会得到更好的帮助......“进行编译时错误检查”(这不是语法英语)并没有削减它。跨度>

标签: c++ c macros compiler-errors


【解决方案1】:

首先,如果宏 BUILD_BUG_ON_ZEROBUILD_BUG_ON_NULL 的参数不同于 0,则会触发编译错误。

如果宏参数是0,它们不会触发任何编译错误,但会为BUILD_BUG_ON_ZERO 生成一个0,为BUILD_BUG_ON_NULL 生成一个(void *) 0

这些宏来自用 C 语言编写的 Linux 内核,它们仅适用于 C 程序。

在 C++ 中,这些宏工作。原因是在 C++ 中,您不能在 sizeof 表达式中声明结构。

如果您是用 C 或 C++ 编译程序,您没有在问题中提及,但我强烈怀疑您是用 C++ 编译它。所以不要在 C++ 中使用这些宏。

【讨论】:

  • 是的,我正在使用 c++ 编译器。谢谢 。现在我得到了它不能在 c++ 中使用的解决方案,因为没有规定在 sizeof 表达式中声明类型..
  • 呃,BUILD_BUG_ON_ZERO 肯定应该表明值为零时有错误。因此!使非零值变为负数并得到错误。
  • @MatsPetersson 您应该再次阅读宏定义:当宏参数为非零时,会发生编译错误。 !! 成语用于规范化布尔参数:0 转到 0,非零转到 1。这些宏名称背后的想法是所有BUILD_BUG_ON* 宏在参数为真时触发编译错误。后缀ZERO 与条件无关,但与宏参数为假时产生的值有关。无论如何,我发现这些宏的名称具有误导性。
  • 好的,是的,你是对的。早上太早了... ;) 我在想 Linux 宏,这绝对是 BUG_ON(truthvalue) - 如果真值是真的,那么它会停止内核。
【解决方案2】:

编辑:该问题最初标记为 C++,但现在仅标记为 C。

我不会追究问题的进一步根本变化。

C++ 标记问题的原始答案:


本源代码:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
int main(){
BUILD_BUG_ON_NULL(0);
}

用g++ 4.7.1编译,生产

foo.cpp:在函数'int main()'中: foo.cpp:4:1:错误:类型可能未在“sizeof”表达式中定义 foo.cpp:4:21:警告:语句无效 [-Wunused-value]

这直接说明了问题所在。

所以最好使用不同的编译器进行编译。


您可能正在寻找编译时断言

对于 C++11,您可以使用 static_assert,例如通过诸如

之类的宏
#define STATIC_ASSERT( e ) static_assert( e, #e )

在 C++03 中,您可以将其实现为有效/无效的 typedef,因为 typedef 可以在同一个翻译单元中重复,并且可以在类定义中使用:

#define STATIC_ASSERT( e ) typedef char staticAssert_shouldBeTrue[e? 1 : -1]

其中一个问题是 g++ 有/有一个编译器错误,其中重复的 typedef 并不总是按应有的方式被接受,因此需要为每个名称生成一个本地唯一的名称,例如通过使用__LINE__

但您始终可以只使用 Boost 库中的定义,因为 Boost 支持大多数现存的编译器,并根据需要对每个编译器进行特殊处理。

【讨论】:

  • 所以你是说我们不能用上述想法进行编译时断言,因为类型已在 sizeof() 表达式中定义?
  • @Learner:C 和 C++ 是不同的语言。以上是 C++ 的答案。您的问题现在仅标记为 C。
【解决方案3】:

gcc -std=c99 -pedantic-errors编译,我得到

screwed.c: In function ‘main’:
screwed.c:5:1: error: negative width in bit-field ‘<anonymous>’
screwed.c:5:1: error: struct has no named members [-pedantic]

这些是当代码编译为 C 时编译应该给出的错误。位域的宽度必须是非负的(如果它有名称,则为正),并且 struct 必须至少有一个命名成员(两个,如果最后一个是灵活数组成员)。允许structs 不带标签。

要么你编译的代码不是 C,要么你的编译器不符合标准。

当编译为 C++ 时,额外的错误

error: types may not be defined in ‘sizeof’ expressions

已生成(但关于struct 没有命名成员的那个消失了)。

在 C++ 中,您可能不会在 sizeof 表达式中定义类型,并且您的编译器选择了一种不太明确的方式来告诉您。

【讨论】:

  • 所以你说上面的方法不是检查编译时错误的正确方法?
  • @Learner 将行 #ifdef __cplusplus #error C++ compiler used #endif 添加到您的程序中,以检查您没有使用 C++ 编译器。
  • 好吧,你想在编译时检测什么?由于你的宏的参数必须是一个常量表达式,它是相当有限的。当参数为0 时,即使在非常严格的模式下也可以通过将命名成员添加到struct 来使其编译,对于非零参数,您将收到“负宽度”错误。如果您只使用一个!,则会切换大小写。
  • @ouah 这应该在每个源文件的顶部;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 2014-03-19
相关资源
最近更新 更多