Const变量在C中用指针改变
变量i
被声明为const,但我仍然可以使用指向它的内存位置的指针来更改该值。 这怎么可能?
int main() { const int i = 11; int *ip = &i; *ip=100; printf("%d\n",*ip); printf("%d\n",i); }
当我编译时,我得到这个警告:
test.c: In function 'main': test.c:11: warning: initialization discards qualifiers from pointer target type
输出就是这个
100 100
const
是一个编译时function。
它不会阻止你在脚下射击自己; 这就是警告的用途。
const
不是对编译器的请求,使得无法更改该变量。 相反,它是对编译器的承诺 ,你不会。 如果你违背承诺,你的程序可以做任何事情,包括崩溃。
例如,如果我使用带有-O2
优化级别的gcc编译示例代码,则输出为:
100 11
允许编译器将const
限定变量放在只读内存中,但它不必(除了其他任何东西,某些环境不实现任何此类事情)。 特别是,将自动(“本地”)变量置于只读存储器中几乎总是不切实际的。
如果您将i
的声明更改为:
static const int i = 11;
然后你可能会发现程序现在在运行时崩溃了。
虽然它可能是C中的警告,但这是C ++中的编译器错误。
如果以某种方式设法在C / C ++中转换此const int
,则可能导致未定义的行为 。 原因是,您正在将一个数字文字(即const int i =
11 ;
)从const
转换为可变值。
您的代码显示的内容与以下序列之间存在差异:
int x = 11; // x is modifiable const int i = x; int *ip = (int*)(&i); // ok *ip=100;
无法修改const
限定对象。 如果进行了此类尝试,则程序将显示未定义的行为(C99 6.7.3.5)。 (你的程序不正确。)
更多关于const
: 可以修改未声明为const
的对象,但不能使用const
-qualified lvalues。 当涉及指针时,这是最明显的。 例如,考虑声明:
int i = 10; int *p1 = &i; const int *p2 = &i;
可以通过i
本身和通过p1
修改i
,但不能通过p2
修改i
。 这意味着*p2
可以计算为不同的值,即使p2
指向const
对象,因为其他语句可能会更改p2
指向的对象(别名指针,如示例中所示)。
但是,如果i
本身是const
限定的,那么尝试通过p1
修改它将产生未定义的行为(正如你的代码那样)。
这不是尝试修改i
导致程序的行为未定义,而是ip
的初始化。
const int i = 11; int *ip = &i;
&i
的类型为const int*
。 ip
的类型为int*
。 尝试使用const int*
值初始化int*
是一种约束违规 。 符合要求的实施需要发布诊断; 一旦完成,它可能会也可能不会拒绝翻译单位。 如果它接受它,则C标准对所得到的程序的行为一无所知。
接受此类事物的编译器通常生成相当于从const int*
到int*
的转换的代码,使得声明实际上等效于:
int *ip = (int*)&i;
但该语言不需要这种行为。
不要忽视警告。
(注意,使用强制转换,代码不违反约束;然后是以下行为
*ip = 100;
未定义,因为它试图修改一个const
限定对象。)
特别是gcc有很多情况,其中约束违规的诊断被处理(默认情况下)作为警告而不是致命错误。 我个人不喜欢gcc; 它允许通过太多糟糕的代码。
(你的程序的行为也是未定义的,因为你在没有可见声明的情况下调用printf
;添加#include
。而int main()
应该是int main(void)
。)