为什么大多数C开发人员使用define而不是const?

在许多程序中,# #define与常量具有相同的用途。 例如。

 #define FIELD_WIDTH 10 const int fieldWidth = 10; 

我通常会看到第一种forms比其他forms更受欢迎,依靠预处理器来处理基本上是应用程序决策的内容。 这个传统有什么理由吗?

这有一个非常可靠的原因:C中的const并不意味着一些常量。 这只是意味着一个variables是只读的。

在编译器需要一个常量的地方(例如非VLA数组的数组大小),使用constvariables(如fieldWidth是不可能的。

他们不一样

const只是一个限定符,它表示一个variables在运行时不能被改变。 但variables的所有其他function仍然存在:已经分配了存储空间,并且可以解决此存储空间问题。 因此,代码不仅仅把它当作一个文字来对待,而是通过访问指定的内存位置来引用variables(除非它是static const ,那么它可以被优化掉),并且在运行时加载它的值。 而作为一个constvariables已经分配了存储空间,如果你把它添加到一个头文件中,并将它包含在几个C源代码中,除非将其标记为extern否则将会出现“多符号定义”链接错误。 在这种情况下,编译器无法根据实际值优化代码(除非进行全局优化)。

#define只是用它的值replace一个名字。 此外,可以在预处理器中使用#ifdef常量:可以使用#ifdef根据其值进行条件编译,也可以使用string化运算符#来获取string的值。 而且由于编译器在编译时知道它的值,所以可以根据这个值优化代码。

例如:

 #define SCALE 1 ... scaled_x = x * SCALE; 

SCALE被定义为1 ,编译器可以消除乘法,因为它知道x * 1 == x ,但是如果SCALE是( externconst ,则需要生成代码来获取值并执行乘法,因为值直到连接阶段才会知道。 ( extern需要使用来自多个源文件的常量。)

更接近于使用#define使用枚举:

 enum dummy_enum { constant_value = 10010 }; 

但是这只限于整数值,并没有#define优点,所以没有被广泛的使用。

当你需要从编译它的某个库中导入一个常量值的时候, const是很有用的,或者如果它和指针一起使用的话。 或者,如果它是通过variables索引值访问的常量值数组。 否则, const#define没有任何优势。

原因是大多数时候,你想要一个常量,而不是一个const限定的variables。 在C语言中,这两者并不是相同的。 例如,variables作为static持续时间对象的初始值设定项的一部分无效,例如非vla数组维度(例如结构中的数组大小或任何数组前C99)。

在R的答案稍微扩展一下: fieldWidth不是一个常量expression式 ; 这是一个const限定variables。 它的直到运行时才build立,所以在需要编译时常量expression式的地方(比如在一个数组声明中,或者在一个switch语句中的一个case标签等),它不能被使用。

与预处理后扩展为常量expression式10的macrosFIELD_WIDTH比较; 这个值在编译时已知的,所以它可以用于数组维度,案例标签等。

要添加到R.和Bart的答案:在C:枚举types常量中只有一种方法来定义符号编译时间常量。 这个标准规定这些是inttypes的。 我个人会写你的例子

 enum { fieldWidth = 10 }; 

但是我觉得C程序员的口味差别很大。

虽然const int并不总是合适的,但是如果你定义了一个整型值,枚举通常会作为#define的替代。 这实际上是我在这种情况下的首选。

 enum { FIELD_WIDTH = 16384 }; char buf[FIELD_WIDTH]; 

在C ++中,这是一个巨大的优势,因为您可以将枚举的范围限定在类或名称空间中,而不能将范围定义为#define。

在C中,你没有命名空间,也不能在一个结构体内枚举枚举的范围,甚至不能确定你的types是否安全,所以我实际上看不到任何主要的优点,尽pipe也许有些C程序员会指出。

根据K&R(第2版,第211页),“const和volatile属性是ANSI标准新增的”。 这可能意味着真正旧的ANSI代码根本就没有这些关键字,这实际上只是一个传统问题。 此外,它表示,编译器应该检测到更改constvariables的尝试,但除此之外可能会忽略这些限定符。 我认为这意味着一些编译器可能不会优化包含constvariables的代码,以便在机器代码中表示为中间值(就像#define一样),这可能会花费额外的时间访问远端内存并影响性能。

一些C编译器会将所有constvariables存储在二进制文件中,如果准备大量的系数可以在embedded式世界中占用大量的空间。

相反:使用const允许在现有的程序上闪烁来改变特定的参数。

在C中定义数字常量的最好方法是使用枚举 。 阅读K&R的The C Programming Language,第39页的相应章节。