块内的 #defining 真的是一种代码气味吗?



我读到块内的 #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

如何对其进行预处理?它是如何工作的?

预处理发生在分析代码之前。 这意味着 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

由于宏的值已更改,因此这是一个错误

预处理器指令根本不关注块作用域,无论如何,它们在编译时都会产生影响。 您的代码示例

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 宏中看到这一点:

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

但请注意,#define 和 #undef 超出了b_tbl的定义,因此它们仍然被人类读取为文件范围。

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

如果你愿意,你可以手动完成:你可以在块内使用#define,并记住在块的末尾做你自己的显式#undef。 但这完全取决于你:编译器不会检查你的工作,或者如果你弄错了,就会警告你。

出于这个原因,它被认为是不好的做法。 (我想这就是你所说的"代码气味"的意思。 这是不好的做法,因为它容易出错,并且没有好的自动方法来捕获任何错误。

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

当然,全局变量也是不受欢迎的。 这与这样一个事实有关,这些天,预处理器#define几乎不受欢迎,所有这些。

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

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

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

#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
}

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

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

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

处理器只关心

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 1

在第一种情况下和

#define MACRO_EXAMPLE 1
#define MACRO_EXAMPLE 2

在第二种情况下。

相关内容

最新更新