我有一个C项目,其中所有代码都在*.c
/ *.h
文件对中组织,我需要在一个文件中定义一个常量值,但是也会在其他文件中使用。我该如何声明和定义这个值?
它应该是static const ...
文件中的*.h
吗?作为extern const ...
文件中的*.h
并在*.c
文件中定义?如果值不是原始数据类型(int
,double
等),那么重要的是char *
还是struct
? (虽然在我的情况下它是double
。)
在*.h
文件中定义内容通常不是一个好主意;一个人应该在*.h
文件中声明事物,但在*.c
文件中定义它们。但是,extern const ...
方法似乎效率低下,因为编译器无法内联该值,而是必须始终通过其地址访问。
我想这个问题的实质是:是否应该在C中的static const ...
个文件中定义*.h
个值,以便在多个地方使用它们?
答案 0 :(得分:8)
我遵循的规则是仅在H文件中声明事物并在C文件中定义它们。您可以在单个C文件中声明和定义,假设它只在该文件中使用。
通过声明,我的意思是通知编译器它的存在,但不为它分配空间。其中包括#define
,typedef
,extern int x
等。
定义为声明分配值并为它们分配空间,例如int x
和const 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 const
与const
是一回事。这样就可以告诉你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
作为函数参数。
关于这个答案有一些评论和评价,所以我测试了我的假设并查看了生成的程序集,这个答案是错误的。基本上#define
和const
会得到相同的结果。