#defining在一个块内真的是代码味道吗?

use*_*921 1 c c++ macros preprocessor

我读到#defining和#undefining在一个块里面是代码味道.这是为什么?另外,我在代码中看到(只是一个显示我在实际代码中的内容的示例),这个编译,

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 1
}
Run Code Online (Sandbox Code Playgroud)

但这不编译,

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}
Run Code Online (Sandbox Code Playgroud)

有错误 warning C4005: 'MACRO_EXAMPLE' : macro redefinition

这是如何预处理的?它是如何工作的?

Nat*_*ica 11

预处理在分析代码之前发生.这意味着if/else被忽略了

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 1
}
Run Code Online (Sandbox Code Playgroud)

实际上被视为

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 1
Run Code Online (Sandbox Code Playgroud)

这是可以的,因为你使用相同的值.另一方面

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}
Run Code Online (Sandbox Code Playgroud)

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 2
Run Code Online (Sandbox Code Playgroud)

并且由于宏的值已经改变,这是一个错误


Ste*_*mit 5

在处理程序#define的其余部分之前,处理器之类的预处理器在概念上运行.除此之外,这意味着预处理器定义不支持块范围.编译器没有注意到你是否在... 块#define内部完成了.没有机制在... 块结束时自动执行.{}#undef{}

您可以手动执行此操作,如果您愿意:您可以#define在块内部使用,并记住#undef在块的末尾显式执行.但这一切都在你身上:编译器不会检查你的工作,或者如果你弄错了就会发出警告.

因此,这被认为是不好的做法.(我想这就是"代码味道"的意思.)这是不好的做法,因为它容易出错,而且没有好的,自动的方式来捕捉任何错误.

如果您使用预处理器#define,它应该是全局的(因为,基本上,它全局的,无论您是否想要它).

当然,全球变量也不受欢迎.而这与以下事实有关:现在,预处理器#define几乎都不受欢迎,所有这些都是如此.

像所有风格问题一样,这个问题可能有点争议.当我说手工制作的块范围预处理器定义是"坏风格"时,这并不意味着有一个反对它们的铁定规则.如果你愿意,而且你知道你在做什么,你可以侥幸逃脱; 这里没有人可以阻止你.(如果您在工作中编写代码,并且根据您公司的样式指南,您可能会在代码审查中受到责骂.)

事实上,我每天在工作中使用的代码库都充满了这些"本地范围"的预处理器定义,因为我的一些前辈认为它们很漂亮.我不喜欢他们,但他们确实工作,他们没有造成问题,所以我们没有开始根除他们的运动.


zwo*_*wol 5

预处理程序指令无论如何都不会阻止范围,无论如何它们都会在编译时产生影响.你的代码示例

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}
Run Code Online (Sandbox Code Playgroud)

是100%相当于写作

    #define MACRO_EXAMPLE 1
    #define MACRO_EXAMPLE 2
if(x == 1000) {
} else {
}
Run Code Online (Sandbox Code Playgroud)

(可能除了调试信息中的行号).现在应该更明显的是为什么这是一个错误.这也是为什么在块内部定义代码气味的原因 - 它们具有文件范围效果,无论如何.

(我依旧记得一个仅在C++中改变它的提议,但我认为它没有去过任何地方.)

很好的风格来定义,只有一个顶层结构具有使用结构之前,权利的任何业务的宏,并再次取消定义它随即.你会看到这个用X-macro,例如:

#define X(a, b, c) b,
const int b_tbl[] = {
    #include "tbl.inc"
};
#undef X
Run Code Online (Sandbox Code Playgroud)

但请注意#define和#undef 不在定义之内b_tbl,因此它们仍然作为文件范围读取给人类.