变量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
答案 0 :(得分:8)
const
是编译时功能
它不会阻止你在脚下射击自己;这就是警告的目的。
答案 1 :(得分:8)
const
不是对编译器的请求,使其无法更改该变量。相反,它是编译器的 promise ,你不会。如果你违背诺言,你的程序可以做任何事情,包括崩溃。
例如,如果我使用具有-O2
优化级别的gcc编译示例代码,则输出为:
100
11
编译器允许将const
限定变量放在只读内存中,但它 <(除了其他任何内容,某些环境不实现任何此类事情)。特别是,将自动(“本地”)变量放在只读存储器中几乎总是不切实际的。
如果您将i
的声明更改为:
static const int i = 11;
然后你可能会发现程序现在在运行时崩溃了。
答案 2 :(得分:3)
虽然它可能是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;
答案 3 :(得分:2)
无法修改const
- 限定对象。如果进行了这样的尝试,程序将表现出未定义的行为(C99 6.7.3.5)。 (您的程序不正确。)
有关const
的更多内容: 声明为const
的对象可以进行修改,但不能使用{{1合格的左值。当涉及指针时,这是最明显的。例如,考虑声明:
const
可以通过int i = 10;
int *p1 = &i;
const int *p2 = &i;
本身和i
修改i
,但不能通过p1
修改p2
。这意味着*p2
可以评估为不同的值,即使p2
指向const
对象,因为其他语句可能会更改{{{ 1}}(别名指针,如示例中所示)。
但是,如果p2
本身是i
- 合格,那么尝试通过const
修改它将产生未定义的行为(正如您的代码所做的那样)。
答案 4 :(得分:0)
不是尝试修改导致程序行为未定义的i
,而是ip
的初始化。
const int i = 11;
int *ip = &i;
&i
的类型为const int*
。 ip
的类型为int*
。尝试使用int*
值初始化const int*
是约束违规。符合要求的实施需要发布诊断;一旦完成,它可能会也可能不会拒绝翻译单位。如果它接受它,C标准就没有说明最终程序的行为。
接受此类操作的编译器通常生成的代码相当于从const int*
到int*
的转换,使声明有效地等同于:
int *ip = (int*)&i;
但该语言不需要此行为。
请勿忽略警告。
(注意,使用强制转换,代码不违反约束;然后是以下行为
*ip = 100;
未定义,因为它尝试修改const
- 限定对象。)
(您的计划行为也未定义,因为您在没有明显声明的情况下致电printf
;添加#include <stdio.h>
。int main()
应为int main(void)
。)