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) 。)