如何找到 C++ 编译器认为定义为常量的内容?

Posted

技术标签:

【中文标题】如何找到 C++ 编译器认为定义为常量的内容?【英文标题】:How do I find something that the C++ compiler thinks is defined as a constant? 【发布时间】:2015-06-29 12:45:06 【问题描述】:

我在尝试构建我的应用程序时报告了以下错误:

错误 C2143:语法错误:在“常量”之前缺少“” 错误 C2143:语法错误:缺少 ';'在“常数”之前 错误 C2059:语法错误:'常量'

对于以下代码:

namespace oP

      enum adjustment
      
         AUTO_OFF,
         AUTO_ONCE,
         AUTO_CONTINUOUS,
         AUTO_SEMI,
         ABSOLUTE,        // The line that the errors point to.
         NUDGE
      ;

小写的“absolute”构建正常,如果我拼错 ABSOLUTE,那么它构建没有错误。

我已经搜索了我的整个代码库,没有其他地方使用“绝对”一词。 我已经调查了没有此更改的构建工件,但在其中找不到任何对 ABSOLUTE 的引用。

有没有人指出问题出在哪里或如何调试?

谢谢

【问题讨论】:

你使用的是哪个编译器? 您可能在某个包含的文件中的某个位置以该名称定义了一个宏。检查它们;更简单的方法是检查预处理器的输出。如果您使用g++,请使用-E 标志在预处理阶段后停止。 我怀疑某些标头(您的或第 3 方的)将 ABSOLUTE 定义为 ::fabs。如果它是 C++ 标准库的一部分,那么这是一个糟糕的实现。 中有一个#include @James 那么你需要使用/E/P。见here。 【参考方案1】:

ABSOLUTE 是 Windows API 标头 <windi.h> 之一中的 #defined(编号为 1)。这就是让编译器感到困惑的地方。

你可以#undef它,如果你不需要它,删除<windows.h>,或者重命名你的枚举。

【讨论】:

【参考方案2】:

您在其中一个包含的文件中的某处以该名称定义了一个宏;检查他们。更简单的方法是检查预处理器的输出。

如果您使用 GCC,请使用 -E 标志在预处理阶段后停止。使用 VC++ 编译器,您应该使用/E 和/或/P。详情请见How do I see a C/C++ source file after preprocessing in Visual Studio?。


通常惯​​例是将宏命名为全部大写;这也适用于枚举,if 您使用 C++03 的(普通)枚举。更好的选择是使用 C++11 的强类型scoped enumerations。

每个条目的名称可以是帕斯卡大小写,并且使用枚举的名称修饰它们变得非常易读Adjustment::Absolute,而不是旧的、无范围的枚举ABSOLUTE。这不是很可读,因为读者可能会将自己与wingdi.h 声明的宏混淆(正如 Bathsheba 指出的那样)。除了可读性之外,它还避免污染封闭的命名空间。

【讨论】:

"这也适用于枚举" 不是真的。 ALL_UPPER_CASE 通常适用于宏,以及通过宏定义的常量。枚举和普通常量可以使用普通的命名约定。 See Qt 4/5 for examples。您还可以将枚举包含在结构和命名空间中,这通常非常有用。 即使使用更强类型的范围枚举,预处理器不会用宏定义替换那些值吗?目前它已经成功地被 oP::ABSOLUTE 引用了。 @SigTerm 当然,这就是为什么它是一个约定,而不是一个固定的规则。但是我见过的大多数代码库都倾向于对宏 枚举使用全部大写。这是一种 C 主义。 @James 是的,即使使用范围枚举,处理器也会盲目地将 ABSOLUTE 替换为宏命名的实际常量。我可以在 GCC 5.1.0 和 VC++ 17.00.61030 上确认这一点。 @legends2k 我认为您对我的问题的评论是对一般问题的更好回答,而不是您作为实际答案提出的答案。【参考方案3】:

您正在使用 Visual c++ 编译器和#include,那么您应该会收到此错误。在 windows.h 中包含文件 #include 并且在wingdi.h 中你会发现

/* Coordinate Modes */
#define ABSOLUTE            1
#define RELATIVE            2

因此发生错误。

【讨论】:

【参考方案4】:

如何找到 C++ 编译器认为定义为常量的内容?

如果您的编译器不愿意生成有用的消息(通常它会打印之前定义术语的位置)或者如果您怀疑自己成为 WinAPI 标头中的宏巫毒的受害者...

选择性地注释掉代码行并重新编译以查明问题。 如果您注释掉一行并且您的程序在此之后编译,则 行是您的问题的根源。如果您的代码块很大,请执行“二分查找” - 注释掉整个块,然后注释掉一半,这样您可以快速缩小问题范围。

在 IDE 中,您通常可以将鼠标悬停在项目上以查看它的定义位置,或者按下某个键或使用上下文菜单“跳转到定义”。

除此之外,您还可以调查预处理器输出。


并且不能有选择地注释掉标头以在它更改时进行测试 - 因为新的编译器警告列表太繁重而无法处理

创建一个空白 *.cpp 文件并将有问题的定义复制到其中,直到您破坏它。这将允许您查明问题。

在您自己的 *.h 文件中始终只包含最少的必要标头集是一种很好的做法,最好完全避免特定于操作系统的标头,尽管在这种情况下这实际上是不可能的。

在您的特定场景中,另一个不错的选择是更改枚举值的命名样式。通常ALL_UPPERCASE 只保留给宏(宏定义和宏常量)。此规则的一个显着例外是在 Windows 标头中定义的 minmax 宏(可以禁用它们)。因为您在enum 中使用了它,所以您与特定于操作系统的定义发生冲突。我会对枚举使用与常量和局部变量相同的命名约定。

【讨论】:

这些是一些有用的启发式方法,但在这种情况下它们不会有帮助。我知道是哪一行代码导致了问题,并且不能有选择地注释掉标头以在它更改时进行测试——因为新的编译器警告列表太繁重而无法解决。刚刚在 Visual Studio 中测试过 - 它无法识别 ABSOLUTE 也在头文件中定义。 @James:最后一段适用于这种情况。除了 IDE 帮助之外,您无法真正知道符号的定义位置。此外,您可以注释掉标题。将有问题的声明复制粘贴到空白 *.cpp 文件中,然后开始添加标题,直到你破坏它。

以上是关于如何找到 C++ 编译器认为定义为常量的内容?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中define(宏定义) 各种用法(含特殊),小举个例子,谢谢!

C++中强行修改const常量的问题

C++中 容易忽视的const 修饰符

C++基础学习(04)——常量

C++基础学习(04)——常量

C++知识点整理