C:`const` 关键字的行为
-
07-07-2019 - |
题
有人告诉我,如果我用 ANSI-C 编码来声明变量的使用顺序,则断言指针不为空并且索引在范围内,并在使用变量之前进行初始化。
如果我声明一个 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<stdio.h>
int main ( void )
{
printf ( "wibble\n" );
{
const int x = 10;
printf ( "x = %d\n", x );
}
return 0;
}
其他提示
const
变量是只读的,必须在定义它们的地方进行初始化。
此代码产生错误:分配只读变量'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;