使用" #define"的替代方案在C ++中?为什么不赞成?

时间:2012-04-21 18:34:03

标签: c++ coding-style global-variables c-preprocessor

我已经开发了不到一年的C ++,但在那段时间里,我听到很多人都在谈论可怕的#define。现在,我意识到它是由预处理器而不是编译器解释的,因此无法调试,但这真的很糟糕吗?

这是一个例子(未经测试的代码,但你得到了一般的想法):

#define VERSION "1.2"

#include <string>

class Foo {
  public:
    string getVersion() {return "The current version is "+VERSION;}
};
  1. 为什么这段代码不好?
  2. 是否可以使用#define

5 个答案:

答案 0 :(得分:11)

  

为什么这段代码不好?

因为VERSION可以被覆盖而且编译器不会告诉你。

  

是否有使用#define的替代方法?

const char * VERSION = "1.2";

const std::string VERSION = "1.2";

答案 1 :(得分:10)

真正的问题是定义是由与语言其余部分(预处理器)不同的工具处理的。因此,编译器不知道它,并且在出现问题时无法帮助您 - 例如重用预处理器名称。

考虑max的情况,有时将其实现为宏。因此,您无法在代码中的任何位置使用标识符max Anywhere的。但编译器不会告诉你。相反,你的代码会出现严重错误,你不知道为什么。

现在,小心一点,这个问题可以最小化(如果没有完全消除)。但是对于#define的大多数用途,无论如何都有更好的选择,因此成本/收益计算变得偏离: no 的好处略有不利。为什么在没有优势的情况下使用有缺陷的功能?

所以这是一个非常简单的图表:

  1. 需要一个常数?使用常量(不是定义)
  2. 需要一个功能吗?使用函数(不是定义)
  3. 需要使用常量或函数无法建模的东西吗?使用定义,但要正确执行。
  4. “正确”地做它本身就是一门艺术,但有一些简单的指导方针:

    1. 使用唯一名称。所有大写字母,始终以唯一的库标识符为前缀。 max?出。 VERSION?出。相反,请使用MY_COOL_LIBRARY_MAXMY_COOL_LIBRARY_VERSION。例如,Boost库,宏的大用户,总是使用以BOOST_<LIBRARY_NAME>_开头的宏。

    2. 谨防评估。实际上,宏中的参数只是被替换的文本。因此,#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))
      
    3. 仍然有很多方法可以让宏发生可怕的错误,而且,重申一下,编译器不会帮助你。

答案 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;