如何找到 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++ 标准库的一部分,那么这是一个糟糕的实现。
/E
或/P
。见here。
【参考方案1】:
ABSOLUTE
是 Windows API 标头 <windi.h>
之一中的 #define
d(编号为 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
/* Coordinate Modes */
#define ABSOLUTE 1
#define RELATIVE 2
因此发生错误。
【讨论】:
【参考方案4】:如何找到 C++ 编译器认为定义为常量的内容?
如果您的编译器不愿意生成有用的消息(通常它会打印之前定义术语的位置)或者如果您怀疑自己成为 WinAPI 标头中的宏巫毒的受害者...
选择性地注释掉代码行并重新编译以查明问题。 如果您注释掉一行并且您的程序在此之后编译,则 那 行是您的问题的根源。如果您的代码块很大,请执行“二分查找” - 注释掉整个块,然后注释掉一半,这样您可以快速缩小问题范围。
在 IDE 中,您通常可以将鼠标悬停在项目上以查看它的定义位置,或者按下某个键或使用上下文菜单“跳转到定义”。
除此之外,您还可以调查预处理器输出。
并且不能有选择地注释掉标头以在它更改时进行测试 - 因为新的编译器警告列表太繁重而无法处理
创建一个空白 *.cpp 文件并将有问题的定义复制到其中,直到您破坏它。这将允许您查明问题。
在您自己的 *.h 文件中始终只包含最少的必要标头集是一种很好的做法,最好完全避免特定于操作系统的标头,尽管在这种情况下这实际上是不可能的。
在您的特定场景中,另一个不错的选择是更改枚举值的命名样式。通常ALL_UPPERCASE
只保留给宏(宏定义和宏常量)。此规则的一个显着例外是在 Windows 标头中定义的 min
和 max
宏(可以禁用它们)。因为您在enum
中使用了它,所以您与特定于操作系统的定义发生冲突。我会对枚举使用与常量和局部变量相同的命名约定。
【讨论】:
这些是一些有用的启发式方法,但在这种情况下它们不会有帮助。我知道是哪一行代码导致了问题,并且不能有选择地注释掉标头以在它更改时进行测试——因为新的编译器警告列表太繁重而无法解决。刚刚在 Visual Studio 中测试过 - 它无法识别 ABSOLUTE 也在头文件中定义。 @James:最后一段适用于这种情况。除了 IDE 帮助之外,您无法真正知道符号的定义位置。此外,您可以注释掉标题。将有问题的声明复制粘贴到空白 *.cpp 文件中,然后开始添加标题,直到你破坏它。以上是关于如何找到 C++ 编译器认为定义为常量的内容?的主要内容,如果未能解决你的问题,请参考以下文章