在C中定义const值

时间:2008-12-10 06:16:35

标签: c const constants header-files code-organization

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

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

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

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

10 个答案:

答案 0 :(得分:8)

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

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

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

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

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

答案 1 :(得分:3)

如果你需要常量(真实的,编译时常量),你可以用这三种方式,把它们放到头文件中(没有什么不好的):

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 ++中,我使用最后一种方法,即静态const double,在这种情况下(注意在C ++中静态将是多余的;它们将自动变为静态,因为它们是const)。在C中,我将继续使用宏。

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

我可以给你一个间接的答案。在C ++中(与C相反)const暗示static。这就是说在C ++中static constconst是一回事。这样就可以告诉你C ++标准组织对这个问题的看法,即所有const都应该是静态的。

答案 5 :(得分:0)

我想看到更多关于你问题的背景信息。值的类型很关键,但是你已经把它遗漏了。 C中const关键字的含义非常微妙;例如     const char * p; 并不意味着指针p是常数;你可以写所有你喜欢的。你不能写的是p指向的内存,即使p的值发生变化,这仍然是正确的。这是我真正了解的唯一案例;一般来说,const的微妙位置的含义是我的意思。但是这个特殊情况对函数参数非常有用,因为它从函数中提取了一个promise,该参数指向的内存不会被突变。

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

我已经写了数万行C;如果我试图追踪它,可能会有数百个。 (wc~ / src / c / * .c表示85,000,但其中一些是生成的,当然还有很多潜伏在其他地方的C代码)。除了这两个案例之外,我从未发现过很多用于const的问题。我很乐意学习一个新的有用的例子。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

标题中的

变量应该真正声明为extern,因为这是隐含的可见性。 有关详细说明,请参阅this question

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

答案 8 :(得分:0)

在C ++中,你应该总是使用

const int SOME_CONST = 17;

表示常量,从不

#define SOME_CONST 17

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

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

答案 9 :(得分:-1)

如果要在函数中内联值,则应使用#define MY_MAGIC_NUMBER 0x12345678
即使static const unsigned MY_MAGIC_NUMBER = 0x12345678也会导致从地址获取值。除非你在循环中有很多价值,否则性能损失并不重要 我只使用const作为函数参数。

关于这个答案有一些评论和评价,所以我测试了我的假设并查看了生成的程序集,这个答案是错误的。基本上#defineconst会得到相同的结果。