【问题标题】:Defining const values in C在 C 中定义 const 值
【发布时间】:2010-09-26 04:40:30
【问题描述】:

我有一个 C 项目,其中所有代码都组织在 *.c/*.h 文件对中,我需要在一个文件中定义一个常量值,但是它也将在其他文件中使用。我应该如何声明和定义这个值?

应该是*.h 文件中的static const ... 吗?作为 *.h 文件中的 extern const ... 并在 *.c 文件中定义?如果该值不是原始数据类型(intdouble 等),而是 char *struct,这有什么关系? (虽然在我的情况下是double。)

*.h 文件中定义东西通常看起来不是一个好主意;应该在*.h 文件中声明事物,但在*.c 文件中定义它们。但是,extern const ... 方法似乎效率低下,因为编译器无法内联该值,而是必须始终通过其地址访问它。

我想这个问题的本质是:是否应该在 C 中的 *.h 文件中定义 static const ... 值,以便在多个地方使用它们?

【问题讨论】:

    标签: c constants header-files code-organization


    【解决方案1】:

    我遵循的规则是只在 H 文件中声明事物并在 C 文件中定义它们。您可以在单个 C 文件中声明和定义,假设它只会在该文件中使用。

    通过声明,我的意思是通知编译器它的存在,但不为其分配空间。这包括#definetypedefextern int x 等。

    定义为声明分配值并为其分配空间,例如int xconst int x。这包括函数定义;将这些包含在头文件中通常会导致代码空间浪费。

    我见过太多初级程序员在将const int x = 7; 放入头文件时感到困惑,然后想知道为什么他们会因为x 被多次定义而出现链接错误。我认为至少你需要static const int x 以避免这个问题。

    我不会太担心代码的速度。很久以前,计算机的主要问题(在速度和成本方面)已从执行速度转移到易于开发。

    【讨论】:

      【解决方案2】:

      如果您需要常量(真实的,编译时常量),您可以通过三种方式进行操作,将它们放入头文件中(这没什么不好):

      enum {
          FOO_SIZE = 1234,
          BAR_SIZE = 5678
      };
      
      #define FOO_SIZE 1234
      #define BAR_SIZE 5678
      
      static const int FOO_SIZE = 1234;
      static const int BAR_SIZE = 5678;
      

      在 C++ 中,我倾向于使用枚举方式,因为它可以限定在命名空间中。对于 C,我使用宏。不过,这基本上归结为品味问题。如果需要浮点常量,就不能再使用枚举了。在 C++ 中,我使用最后一种方式,即 static const double,在这种情况下(注意在 C++ 中静态将是多余的;它们会自动变为静态,因为它们是 const)。在 C 中,我会继续使用宏。

      这是一个神话,使用第三种方法会以任何方式减慢您的程序。我只是更喜欢枚举,因为你得到的值是右值——你不能得到他们的地址,我认为这是一个额外的安全。此外,编写的样板代码要少得多。眼睛集中在常数上。

      【讨论】:

        【解决方案3】:

        您真的需要担心内联的优势吗?除非您正在编写嵌入式代码,否则请坚持可读性。如果它真的是一个神奇的数字,我会使用定义;我认为 const 更适合 const 版本字符串和修改函数调用参数。也就是说,.c 中的定义,.h 中的声明规则绝对是一个相当普遍接受的约定,我不会因为您可能保存内存查找而破坏它。

        【讨论】:

          【解决方案4】:

          作为一般规则,您不要在标题中将事物定义为static。如果您确实在标头中定义了static 变量,则使用标头的每个文件都会获得其自己的声明static 的私​​有副本,这是DRY 原则的对立面:don不要重复自己

          因此,您应该使用替代方案。对于整数类型,使用 enum(在头文件中定义)非常强大;它也适用于调试器(尽管更好的调试器也可以帮助处理#define 宏值)。对于非整数类型,标头中的 extern 声明(可选地用 const 限定)和一个 C 文件中的单个定义通常是最好的方法。

          【讨论】:

          • 不违反 DRY。 - 你不是在重复你自己,编译器在重复你。空间效率不是 DRY 的目的,请查一下。 -1.
          • @rix0rr:显然,您对情况有不同的看法。但是,如果您的标头定义了静态对象,我的代码不太可能使用它们。有特殊的例外 - 但它们是例外。
          【解决方案5】:

          我希望了解您的问题的更多背景信息。值的类型很关键,但您忽略了它。 C 中 const 关键字的含义相当微妙;例如 常量字符 *p; 并不意味着指针 p 是一个常数;你可以随心所欲地写p。你不能写的是 p 指向的内存,即使 p 的值发生变化,这仍然是正确的。这是我真正理解的唯一案例;一般来说,我不知道 const 的微妙位置的含义。但是这种特殊情况对于函数参数非常有用,因为它从函数中提取参数指向的内存不会发生变化的承诺。

          每个人都应该知道另一种特殊情况:整数。几乎总是,常量的命名整数应该在 .h 文件中定义为枚举文字。枚举类型不仅允许您以自然的方式将相关的常量组合在一起,而且还允许您在调试器中看到这些常量的名称,这是一个巨大的优势。

          我写了几万行C;如果我试图追踪它,可能有数百个。 (wc ~/src/c/*.c 说 85000,但其中一些是生成的,当然还有很多 C 代码潜伏在其他地方)。除了这两种情况之外,我从来没有发现 const 有什么用处。我很乐意学习一个新的有用的例子。

          【讨论】:

            【解决方案6】:

            我可以给你一个间接的答案。在 C++(相对于 C)中,const 意味着 static。也就是说在 C++ 中static constconst 是一回事。这样就可以告诉您 C++ 标准机构对这个问题的看法,即所有 consts 都应该是静态的。

            【讨论】:

              【解决方案7】:

              对于 autoconf 环境: 您也可以始终在配置文件中定义常量。 AC_DEFINE() 我猜是在整个构建中定义的宏。

              【讨论】:

                【解决方案8】:

                回答您问题的本质:
                您通常想在头文件中定义静态变量。
                这将导致您在包含标题的每个翻译单元(C 文件)中都有重复的变量。

                标头中的变量实际上应该声明为 extern,因为这是隐含的可见性。 请参阅this question 以获得很好的解释。

                实际上,情况可能并不那么可怕,因为编译器可能会将 const 类型转换为文字值。但是您可能不想依赖这种行为,尤其是在关闭优化的情况下。

                【讨论】:

                  【解决方案9】:

                  在 C++ 中,您应该始终使用

                  const int SOME_CONST = 17;
                  

                  对于常量,从不

                  #define SOME_CONST 17
                  

                  定义几乎总是会在以后回来咬你。常量在语言中,并且是强类型的,所以你不会因为一些隐藏的交互而得到奇怪的错误。我会将 const 放在适当的头文件中。只要它是#pragma once(或#ifndef x / #define x / #endif),就不会出现任何编译错误。

                  在原版 C 中,您可能会遇到必须使用 #defines 的兼容性问题。

                  【讨论】:

                  • const 不能作为case 标签、数组大小或创建新的constconst int SEC_PER_MIN = 60; const int SEC_PER_HOUR = SEC_PER_MIN * 60; 不起作用)。在那里查看 Leffler 的精彩子弹列表:stackoverflow.com/questions/1674032/static-const-vs-define-in-c
                  • 我习惯了 C++。我已经修改了我的答案以指定这一点,因为大多数人在提到 c 时,使用 c++ 编译器进行编译。
                  • @FryGuy:真的吗?我通常在使用 C 时使用 C 编译器,在使用 C++ 时使用 C++ 编译器。
                  • 你真的应该使用 const static.. 否则如果它是一个对象,每次使用都会创建很多实例。
                  猜你喜欢
                  • 2018-05-24
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-10-04
                  • 2019-02-07
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多