我已经开发了不到一年的C ++,但在那段时间里,我听到很多人都在谈论可怕的#define
。现在,我意识到它是由预处理器而不是编译器解释的,因此无法调试,但这真的很糟糕吗?
这是一个例子(未经测试的代码,但你得到了一般的想法):
#define VERSION "1.2"
#include <string>
class Foo {
public:
string getVersion() {return "The current version is "+VERSION;}
};
#define
?答案 0 :(得分:11)
为什么这段代码不好?
因为VERSION可以被覆盖而且编译器不会告诉你。
是否有使用#define的替代方法?
const char * VERSION = "1.2";
或
const std::string VERSION = "1.2";
答案 1 :(得分:10)
真正的问题是定义是由与语言其余部分(预处理器)不同的工具处理的。因此,编译器不知道它,并且在出现问题时无法帮助您 - 例如重用预处理器名称。
考虑max
的情况,有时将其实现为宏。因此,您无法在代码中的任何位置使用标识符max
。 Anywhere的。但编译器不会告诉你。相反,你的代码会出现严重错误,你不知道为什么。
现在,小心一点,这个问题可以最小化(如果没有完全消除)。但是对于#define
的大多数用途,无论如何都有更好的选择,因此成本/收益计算变得偏离: no 的好处略有不利。为什么在没有优势的情况下使用有缺陷的功能?
所以这是一个非常简单的图表:
“正确”地做它本身就是一门艺术,但有一些简单的指导方针:
使用唯一名称。所有大写字母,始终以唯一的库标识符为前缀。 max
?出。 VERSION
?出。相反,请使用MY_COOL_LIBRARY_MAX
和MY_COOL_LIBRARY_VERSION
。例如,Boost库,宏的大用户,总是使用以BOOST_<LIBRARY_NAME>_
开头的宏。
谨防评估。实际上,宏中的参数只是被替换的文本。因此,#define MY_LIB_MULTIPLY(x) x * x
被破坏:它可以用作MY_LIB_MULTIPLY(2 + 5)
,从而产生2 + 5 * 2 + 5
。不是我们想要的。为了防范这种情况,总是 parenhesise 所有使用的参数(除非你知道完全你正在做什么 - 剧透:你可能不会' t;甚至专家也常常惊慌失措地说错了。
此宏的正确版本为:
#define MY_LIB_MULTIPLY(x) ((x) * (x))
但仍然有很多方法可以让宏发生可怕的错误,而且,重申一下,编译器不会帮助你。
答案 2 :(得分:4)
#define
本身并不坏,只是容易被滥用。对于像版本字符串这样的东西,它工作正常,虽然const char*
会更好,但许多程序员使用它远不止于此。例如,使用#define
作为typedef是很愚蠢的,在大多数情况下,typedef会更好。所以#define
语句没有任何问题,没有它们就有些事情无法完成。必须根据具体情况对其进行评估。如果你能在不使用预处理器的情况下找到解决问题的方法,那么就应该这样做。
答案 3 :(得分:2)
我不会使用#define
来定义常量使用static
关键字或更好
const int kMajorVer = 1;
const int kMinorVer = 2;
要么
const std::string kVersion = "1.2";
Herb sutter在这里有一篇很好的文章,详细说明为什么#define
是坏的,并列举了一些实际上没有其他方法可以实现同样的事情的例子:http://www.gotw.ca/gotw/032.htm。
基本上就像许多事情一样,只要你正确使用它就很好但很容易被滥用,宏观错误特别神秘并且需要调试。
我个人将它们用于条件调试代码以及变体数据表示,这在sutter文章的末尾有详细说明。
答案 4 :(得分:0)
通常,预处理器很糟糕,因为它会创建一个不安全的双通道编译过程,会导致难以解码错误消息并导致难以读取的代码。如果可能,你不应该使用它:
const char* VERSION = "1.2"
但是,如果没有预处理器,有些情况下你无法做你想做的事情:
#define Log(x) cout << #x << " = " << (x) << endl;