首页 文章

C常量的最佳实践

提问于
浏览
19

我有一大堆常量,我想在我的代码的不同部分访问,但我希望能够轻松访问整个:

static const bool doX = true;
static const bool doY = false;
static const int maxNumX = 5;

等等

所以我创建了一个名为“constants.h”的文件,并将它们全部放在那里,并将#included包含在任何需要知道常量的文件中 .

问题是,这对于编译时来说很糟糕,因为每次更改常量时,都必须重建constants.h引用的所有文件 . (另外,据我所知,因为它们是静态的,所以每次在新的.cpp中包含constants.h时,我都会在代码中生成doX / doY / maxNumX的副本,导致在编译时浪费千字节的空间EXE - 有没有办法看到这个?) .

所以,我想要一个解决方案 . 如果可能的话,不是“仅在使用它们的文件中声明常量” .

有什么建议?

6 回答

  • 0

    另一种最适合编译时间的方法(但运行时成本较低)是通过类中的静态方法使常量可访问 .

    //constants.h
    class Constants
    {
    public:
      static bool doX();
      static bool doY();
      static int maxNumX();
    };
    
    //constants.cpp
    bool Constants::doX() { return true; }
    bool Constants::doY() { return false; }
    int Constants::maxNumX() { return 42; }
    

    这种方法的优点是,如果在 Headers 中添加/删除/更改方法的声明,则只重新编译所有内容,而更改任何方法返回的值只需要编译constants.cpp(当然还有链接) .

    与大多数情况一样,这可能是最好的,也可能不是你的具体情况,但这是另一种选择 .

  • 3

    唯一的选择是使你的常量 extern 并在另一个 .cpp 文件中定义它们,但是你知道它们在编译每个.cpp`时有什么 Value .

    顺便说一句,不要担心大小增加:对于整数类型,您的常量可能直接在生成的机器代码中内联 .

    最后, static 不是必需的,因为默认情况下 const 全局变量在C中是 static .

  • 2

    您在标头中将它们声明为 extern ,并在实现文件中定义它们 .

    这样,当您想要更改它们的值时,您将修改实现文件,并且不需要完全重新编译 .

    您的变体中的问题不是与编译相关的,而是与逻辑相关的 . 它们不是全局变量,因为每个翻译单元都有自己的变量副本 .

    编辑:

    C -ish的做法实际上将它们包装在一个类中:

    //constants.h
    class Constants
    {
    public:
       static const bool doX;
       static const bool doY;
       static const int maxNumX;
    }
    
    //constants.cpp
    const bool Constants::doX = true;
    const bool Constants::doY = false;
    const int Constants::maxNumX = 5;
    
  • 6

    我认为你的基本假设是关闭的 .

    您的其他 Headers 通常是通过将哪些 Headers 组合在一起来组织的 . 例如,一个类及其相关方法或两个类严重相互关联 .

    为什么要将所有常量分组到一个 Headers 中?它没有任何意义 . 它与 "global.h" Headers 一样简单,可以轻松地包含每一个依赖项 .

    通常,常量用于特定上下文中 . 例如,枚举用作特定函数的标志:

    class File {
    public:
      enum class Mode {
        Read,
        Write,
        Append
      };
    
      File(std::string const& filename, Mode mode);
    
      // ...
    };
    

    在这种情况下,这些常量与它们绑定的类(甚至在类中)之间存在于相同的头中是很自然的 .

    另一类常量是那些只渗透整个应用程序的常量 . 例如:

    enum class Direction {
      Up,
      Down,
      Right,
      Left,
      Forward,
      Backward
    };
    

    ...在一个游戏中,你想要表达物体对他们所面对方向的移动 .

    在这种情况下,为这组特定的常量创建一个头文件很好 .

    如果你真的担心将这些文件组合在一起:

    constants/
      Direction.hpp
      Sandwich.hpp
      State.hpp
    

    当你添加一个常量时,你会巧妙地回避重新编译整个应用程序的问题......但如果你需要,那么,你只付出一次成本,比你必须付出的错误设计更好和你的其余工作一起生活 .

  • 9

    What is the problem with this usage?
    不要在头文件中声明 static 类型,它不会按照您的想法执行 .

    当您在头文件中声明静态时,会在每个包含该头文件的_1869550中创建该变量的副本,因此每个TU都会看到一个不同的变量,这与您对全局变量的期望相反 .

    Suggested Solution:
    您应该在头文件中将它们声明为 extern ,并在一个cpp文件中定义它们,同时在每个要访问它们的cpp文件中包含带 extern 的标头 .

    Good Read:
    How should i use extern?

  • 6

    直接的方法是,创建非const符号:

    const bool doX = true;
    const bool doY = false;
    const int maxNumX = 5;
    

    这些值将由具有给定值的编译器替换 . 这是最有效的方式 . 当然,这也会在您修改或添加值时立即重新编译 . 但在大多数情况下,这不应该引起实际问题 .

    当然有不同方案:

    • 使用 static const ,(或静态const类成员)可以修改这些值而无需重新编译所有引用的文件 - 但是这些值保存在将在运行时调用而不是在编译时解析的const数据段中 . 如果运行时性能没有问题(因为90%的大多数典型代码都没有问题) .

    • 直接的C方式是使用类 enums 而不是全局const标识符(如我所说的Mathieu) . 这是更安全的类型,除此之外它的工作原理如下 const :符号将在编译时解析 .

相关问题