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

时间:2018-05-17 15:12:45

标签: c++ c macros preprocessor

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

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 1
}

但这不能编译,

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}

错误warning C4005: 'MACRO_EXAMPLE' : macro redefinition

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

5 个答案:

答案 0 :(得分:11)

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

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 1
}

实际上被视为

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 1

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

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}

变为

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 2

并且因为宏的值已经改变,所以它是一个错误

答案 1 :(得分:5)

处理程序,处理#define之类的事情,在解析程序的其余部分之前进行概念操作。除此之外,这意味着预处理器定义不支持块范围。如果您在#define ... {块内完成},则编译器不会注意到。没有机制可以在#undef ... {块结束时自动执行}

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

由于这个原因,它被认为是不好的做法。 (我想这就是你的意思"代码味道"。)这是一种不好的做法,因为它容易出错,并且没有好处,自动捕捉任何错误的方式。

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

当然,全球变量也不受欢迎。这与以下事实有关:现在,预处理器#define非常不满,所有这些都是。

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

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

答案 2 :(得分:5)

预处理程序指令无需任何限制来阻止作用域,无论如何它们都会在编译时产生影响。你的代码示例

if(x == 1000) {
    #define MACRO_EXAMPLE 1
} else {
    #define MACRO_EXAMPLE 2
}

100%相当于写作

    #define MACRO_EXAMPLE 1
    #define MACRO_EXAMPLE 2
if(x == 1000) {
} else {
}

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

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

良好的风格来定义一个宏,只有一个顶级构造在该构造之前有任何业务使用权,并且之后立即再次取消定义。您可以使用X-macros查看此内容,例如:

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

但是请注意#define和#undef 是<{1}}的定义,因此它们仍然作为文件范围读取给人类。

答案 3 :(得分:2)

宏由预处理器处理,预处理器在实际编译之前运行。预处理器将文件视为纯文本,具有预处理器逻辑,与源代码逻辑不同。 使用undef

#undef MACRO_EXAMPLE

这将取消定义,以便您稍后重新定义。 风格不佳但会起作用

if(x == 1000) {
    #define MACRO_EXAMPLE 1
    //some code using the macro. Here it is expanded as 1
    #undef MACRO_EXAMPLE
} else {
    #define MACRO_EXAMPLE 2
    //some code using the macro. Here it is expanded as 2
    #undef MACRO_EXAMPLE
}

答案 4 :(得分:0)

  

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

if-else行不会影响预处理器。

就预处理器而言,这些行可能也不存在。

处理器只关心

    #define MACRO_EXAMPLE 1
    #define MACRO_EXAMPLE 1

在第一种情况下和

    #define MACRO_EXAMPLE 1
    #define MACRO_EXAMPLE 2

在第二种情况下。