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

C. *_*oss 90 c coding-style c-preprocessor

在许多程序中,a #define用作与常量相同的目的.例如.

#define FIELD_WIDTH 10
const int fieldWidth = 10;
Run Code Online (Sandbox Code Playgroud)

我通常认为第一种形式优先于另一种,依靠预处理器来处理基本上是应用程序的决定.这个传统有原因吗?

Bar*_*nau 157

这有一个非常可靠的原因:const在C中并不意味着某些东西是不变的.它只是意味着变量是只读的.

在编译器需要真常量的地方(例如非VLA数组的数组大小),使用const变量,例如fieldWidth不可能.

  • 来自不熟悉C的C++程序员的错误海洋中+1的正确答案 (45认同)
  • @Exception:C和C++在处理`const`时是非常不同的语言.在C++中,`const`可以用于适当的常量,在C中则不能. (4认同)
  • @C.罗斯:一致性.所有清单常量通常用`#define`s定义.`const`仅用于表示只读(a的访问路径)变量.我知道,C中的`const`只是简单的坏了:-) (3认同)
  • @fahad:不在C89.在C99中,您可以为自动存储持续时间的变量执行此操作,但从技术上讲,它是VLA. (3认同)
  • 你不能说像 const int size 4 之类的东西;然后再做 char str[size]? (2认同)
  • @fahad:VLA是一个'可变长度数组'.它是一个数组,其大小直到运行时才知道,并且只能用于自动变量(即只能在堆栈上分配). (2认同)
  • 不仅`const`不能用于非VLA数组大小,它也不能用于创建其他`const`.例如:`const uint8_t SECONDS_PER_MINUTE = 60U; const uint16_t SECONDS_PER_HOUR = 60U*SECONDS_PER_MINUTE;`.我想念一种有类型常量的方法(`const`不是常数,正如@Bart写的那样). (2认同)

Vov*_*ium 23

他们是不同的.

const只是一个限定符,它表示变量在运行时无法更改.但变量的所有其他功能仍然存在:它已分配存储,并且可以解决此存储.所以代码不只是将它视为文字,而是通过访问指定的内存位置来引用变量(除非它是static const,然后它可以被优化掉),并在运行时加载它的值.并且,当const变量已分配存储时,如果将其添加到标头并将其包含在多个C源中,除非将其标记为"否则",否则会出现"多符号定义"链接错误extern.在这种情况下,编译器无法针对其实际值优化代码(除非启用全局优化).

#define只需用名称替换名称即可.此外,#define可以在预处理器中使用'd常量:您可以使用它#ifdef来根据其值进行条件编译,或使用字符串化运算符#来获取其值的字符串.当编译器在编译时知道它的值时,它可以根据该值优化代码.

例如:

#define SCALE 1

...

scaled_x = x * SCALE;
Run Code Online (Sandbox Code Playgroud)

SCALE定义为1编译器可以消除乘法,因为它知道x * 1 == x,但如果SCALE是(extern)const,它将需要生成代码来获取值并执行乘法,因为在链接阶段之前将不知道该值.(extern需要使用来自多个源文件的常量.)

与使用更接近的#define是使用枚举:

enum dummy_enum {
   constant_value = 10010
};
Run Code Online (Sandbox Code Playgroud)

但是这仅限于整数值并且没有优势#define,因此它没有被广泛使用.

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

  • `#define`优于`enum`的优点是你可以`#ifdef`来测试它的存在或者在`#if`中使用它的值,这使它对控制构建时选择或提供功能更有用这可能存在于某些平台上但不存在于其他平台上. (3认同)
  • 关于优化的部分对于任何进行链接时优化的编译器都不适用. (2认同)

R..*_*R.. 14

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

  • 具有静态存储持续时间的数组.复合文字数组.具有文件范围的`typedef`中使用的数组类型.也许其他人. (2认同)

Joh*_*ode 8

扩展R的答案一点:fieldWidth不是一个恒定的表达 ; 这是一个const合格的变量.它的直到运行时才建立,因此不能在需要编译时常量表达式的地方使用它(例如在数组声明中,或在switch语句中使用case标签等).

与宏相比FIELD_WIDTH,预处理后的宏扩展为常量表达式10; 这个值在编译时已知的,所以它可用于阵列的尺寸,壳体标签等

  • 所以`const`的操作更像java的`final`,只允许一个赋值? (2认同)

Jen*_*edt 6

要添加到R.和Bart的答案:在C中只有一种方法可以定义符号编译时常量:枚举类型常量.该标准规定这些是类型int.我个人会把你的例子写成

enum { fieldWidth = 10 };
Run Code Online (Sandbox Code Playgroud)

但我猜C程序员的口味差异很大.