C:`const`关键字的行为
我被告知如果我在ANSI-C中编码以按照将使用变量的顺序声明,断言指针不是null并且索引在边界内,并且在使用变量之前初始化。
如果我声明一个const,我可以在一个断言和代码块后初始化它吗? 在Java中,最终的初始化必须在声明时进行,但是通过ANSI-C实现它是一致的,我可以初始化const一次但不一定在声明时?
Java编译器具有少量流逻辑,允许您在声明后初始化final
变量。 这是合法的Java:
final int something; if ( today == Friday ) something = 7; else something = 42;
Java将检测是否有任何分支未定义最终值。 它不会分析条件,所以这不是合法的Java,即使它在逻辑上相似:
final int something; if ( today == Friday ) something = 7; if ( today != Friday ) something = 42;
在ANSI C89中,必须在声明它们的语句中初始化const
变量(除extern
)。
const int something = ( today == Friday ) ? 7 : 42;
声明中的extern
修饰符告诉编译器变量是在不同的编译单元(或此编译单元中的其他位置)初始化的。
在ANSI C99中,您可以混合声明和代码,因此您可以在断言和代码块之后声明和初始化const
变量。 1999 ANSI C的可移植性仍然是一个问题。
解决C89的问题是注意代码之前的声明规则在块范围而不是函数范围内工作,因此您可以这样做:
#include int main ( void ) { printf ( "wibble\n" ); { const int x = 10; printf ( "x = %d\n", x ); } return 0; }
const
变量是只读的,必须在定义它们的地方初始化。
此代码产生error: assignment of read-only variable 'foo'
(gcc4):
const int foo; foo = 4;
对于const指针也是如此(请注意: const int *
不是const指针,而是指向const的指针):
int * const foo; foo = 4;
请注意,即使在C89中,您也可以通过引入一个仅用于额外范围的裸块来将定义更接近第一次使用的位置。 之前:
int a, b, c; a = 12; // do some stuff with a b = 17; // do some stuff with a and b c = 23; // do some stuff with a, b, and c
后:
int a = 12; // do some stuff with a { int b = 17 // do some stuff with a and b { int c = 23; // do some stuff with a, b and c } }
当然,使用C99,您可以定义除块开头之外的变量:
int a = 12; // do some stuff with a int b = 17 // do some stuff with a and b int c = 23; // do some stuff with a, b and c
您无法在函数体内声明后初始化const,但您可以在断言后打开一个块:
void func() { int y; //do assertions assert(something); { int const x = 5; // function body } }
除了块范围和其他已经显示的C99声明方法之外,答案是否定的; 你不能推迟const变量的初始化。 无论如何,const对局部变量不是很有用。 我在C中使用const关键字的主要时间是:
- 函数参数(或基于参数的局部变量指针)中的指针,其中函数遵守不修改指向数据的约定。 const关键字有助于确保函数实现遵守不修改的要求(它需要特殊的工作量来摆脱const)并允许此要求通过多个函数调用传播。
- 用于声明我想要存储在二进制文件的只读部分中的编译时常量表(查找表,预定义永久对象等),以便它们在运行时不使用额外的物理资源。
我有时会声明局部变量const,如果我认为它会帮助读者理解一个函数,但这种情况非常罕见。
如果你在谈论拆分定义
const int x = 2;
分为两部分:
const int x; x=2;
我担心在C中是不可能的。
如果我是你,我会尽力确保理解你描述的编码规则的意图。 我怀疑理智的编码规则会阻止初始化变量(甚至是非常量变量)。
回应各种评论:
const int * p;
不是const变量的声明。 它是对const int的非const指针变量的声明。
你可以申报
extern const int x;
但是在执行代码,断言检查后,你仍然无法初始化x ……
如果你想在LHS上抛弃const,那怎么样?
const int n = 0; *((int*)&n) = 23;