【问题标题】:Having a constant to be used across entire application. Use #define or variable [duplicate]在整个应用程序中使用一个常量。使用#define 或变量[重复]
【发布时间】:2011-04-19 03:41:09
【问题描述】:

可能重复:
static const vs #define

大家好,在 C++ 中,定义一个在整个应用程序中使用的常量,你们通常的做法是什么?

#define WINDOWS_HEIGHT 1024

const int WINDOWS_HEIGHT = 1024;

谢谢。

【问题讨论】:

标签: c++


【解决方案1】:

enum不用担心链接怎么样?

【讨论】:

  • 除了链接问题之外,它应该可以更快地访问并且在某些情况下可以给编译器一些有用的提示:如果some_const恰好为0,x ^= some_const;将不会产生任何代码。跨度>
  • 枚举器的问题在于它的大小是实现定义的。不知道这在 C++0x 中是否有所改变
  • @Chubsdad:在 C++ 中,您可以通过指定初始化程序来控制枚举类型。在 C 中,类型是 int
  • 我同意,特别是因为我在 C 中的工作量与(或超过)C++ 一样多,并且 const 变量不适用于您希望在 C 中使用的所有内容。但我发现我是少数。其他团队成员似乎经常发现将枚举用于任意常量有点令人困惑/不安。我发现#define 更受欢迎。 +1
  • @Michael:“在 C++ 中,您可以通过指定初始化程序来控制枚举类型”。那会是什么样子?我认为你可能会通过包含一个负值来影响符号,或者知道跨越枚举所需的最小大小,但你不能任意阻止它使用超过你想要的或强制它在小范围内使用无符号类型.. .? (我知道您可以探测编译器的行为并推断出一些特定于实现的黑客行为。)
【解决方案2】:

各有优劣,视使用情况而定:

  • 枚举
    • 仅适用于整数值
    • 妥善处理范围/标识符冲突问题
    • 强类型,但有足够大的有符号或无符号 int 大小,您无法控制(在 C++03 中)
    • 无法获取地址
    • 更强的使用限制(例如递增 - template <typename T> void f(T t) { cout << ++t; } 不会编译)
    • 每个常量的类型取自封闭的枚举,因此template <typename T> void f(T) 从不同的枚举传递相同的数值时会获得不同的实例化,所有这些都不同于任何实际的 f(int) 实例化。
    • 即使使用 typeof,也不能指望 numeric_limits 提供有用的见解
    • 枚举的类型名可能出现在 RTTI、编译器消息等的不同位置 - 可能有用,可能会混淆
  • 常量
    • 妥善处理范围/标识符冲突问题
    • 强大的、单一的、用户指定的类型
    • 一个定义规则的复杂性
  • 定义
    • “全局”范围/更容易出现冲突使用,这可能会产生难以解决的编译问题和意外的运行时结果,而不是正常的错误消息;减轻这种情况需要:
      • 长、晦涩和/或集中协调的标识符,以及对它们的访问无法从隐式匹配 used/current/Koenig-looked-up 命名空间、命名空间别名等中受益。
      • 通常需要使用所有大写字符并保留给预处理器定义(企业规模预处理器使用保持可管理性的重要指南,并且可以预期遵循哪些第 3 方库),观察这意味着迁移现有的 const 或定义的枚举涉及大小写的更改(因此会影响客户端代码)。 (就我个人而言,我将枚举的第一个字母大写,但不是 const,所以无论如何我都会被打到这里——也许是时候重新考虑一下了。)
    • 可能的更多编译时操作:字符串文字连接、字符串化(取其大小)
      • 缺点是考虑到#define X "x" 和一些客户端使用ala "pre" X "post",如果您想要或需要使X 成为运行时可更改的变量而不是常量,那么您就有麻烦了,而从@ 转换更容易987654325@ 或 const std::string,因为它们已经强制用户合并连接操作。
    • 不能直接在定义的数值常量上使用 sizeof
    • 无类型(与无符号相比,GCC 不会发出警告)
    • 某些编译器/链接器/调试器链可能不显示标识符,因此您只能查看“幻数”(字符串,等等...)
    • 无法获取地址
    • 在创建#define 的上下文中,替换值不必是合法的(或离散的),因为它在每个使用点进行评估,因此您可以引用尚未声明的对象,具体取决于“实现”不需要预先包含,创建“常量”,例如可用于初始化数组的 { 1, 2 },或 #define MICROSECONDS *1E-6 等。(绝对不推荐这样做!)
    • 一些特殊的东西,如__FILE____LINE__ 可以合并到宏替换中

作为一般规则,我使用 const 并认为它们是最专业的通用选项(尽管其他的简单性吸引了这位老懒程序员)。

【讨论】:

    【解决方案3】:

    嗯,取决于。对于整数常量enum 效果很好。比如:

    struct Constants {
        enum {
            WindowHeight = 8,
            WindowWidth  = 8,
            // ...
        };
    };
    ...
    int h = Constants::WindowHeight;
    

    【讨论】:

      【解决方案4】:

      使用常量整数;它将显示在调试器中,该 #define 值可能不会出现。或者使用枚举;这也有效。

      【讨论】:

        【解决方案5】:

        我投票赞成在一个翻译单元中定义的“命名空间范围外部常量”变量。命名空间范围“const”变量具有内部链接。

        【讨论】:

          【解决方案6】:

          我使用命名空间范围 extern const。

          【讨论】:

            【解决方案7】:

            使用定义只是将代码中所有出现的地方替换为该值。一个 const 全局变量几乎相同,只是类型可以显式定义。这几乎是唯一的区别。

            就个人而言,我更喜欢使用定义,只是出于品味。

            但是,我不认为有任何区别。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-03-15
              • 1970-01-01
              • 2013-10-23
              • 1970-01-01
              • 2013-11-04
              • 2011-09-07
              • 2018-09-18
              • 2020-07-27
              相关资源
              最近更新 更多