我们可以通过指针改变用const定义的对象的值吗?
#include int main() { const int a = 12; int *p; p = &a; *p = 70; }
它会起作用吗?
它是“未定义的行为”,意味着基于标准,您无法预测尝试此操作时会发生什么。 根据特定的机器,编译器和程序状态,它可能会执行不同的操作。
在这种情况下,最常发生的是答案是“是”。 变量const或非变量只是内存中的一个位置,您可以打破常量规则并简单地覆盖它。 (当然,如果程序的某些其他部分依赖于其const数据是恒定的,这将导致严重的错误!)
但是在某些情况下 – 最常见的是const static
数据 – 编译器可能会将这些变量放在只读的内存区域中。 例如,MSVC通常将const static int放在可执行文件的.text段中,这意味着如果您尝试写入操作系统将引发保护错误,程序将崩溃。
在编译器和机器的其他组合中,可能会发生完全不同的事情。 您可以肯定的一点是,这种模式会让任何必须阅读您的代码的人烦恼。
这是未定义的行为。 certificate:
/* program.c */ int main() { const int a = 12; int* p; p = &a; *p = 70; printf("%d\n", a); return 0; } gcc program.c
并运行它。 输出为70(gcc 4.3)
然后像这样编译它:
gcc -O2 program.c
并运行它。 输出将是12.当它进行优化时,编译器可能会将12加载到寄存器中,并且在需要访问printf时不会再次加载它,因为它“知道”a不能更改。
通过指针修改const
限定对象会调用未定义的行为,结果就是这样。 它可能是你期望的东西,即。 如果已放入.text
等,则前一个值不变
它确实适用于gcc。 它不喜欢它:
test.c:6:警告:赋值从指针目标类型中丢弃限定符
但是执行时价值确实发生了变化。 我不会指出明显的禁忌……
是的,你可以通过使用这样的代码完成它。 但是当a
是全局的时(gcc编译的程序给我segmentation fault
),代码不适用。
一般来说,在心爱的C中,你几乎总能找到一些不应该被改变或暴露的东西。 这里的const就是一个例子。
但考虑到这个可怜的家伙(也许是我自己6个月后)维护我们的代码,我经常选择不这样做。
这里指针p
的类型是int*
,它被赋值为const int*
的类型( &a
=> const int
变量的地址)。
隐式强制转换消除了常量,但gcc会发出警告(请注意这在很大程度上取决于实现)。
由于指针未声明为const
,因此可以使用此指针更改值。
如果指针被声明为const int* p = &a
,则无法执行*p = 70
。
您不能通过使用指向它的指针来更改常量变量的值。 这种类型的指针称为Pointer to a constant
。
还有另一种称为Constant Pointer
概念。 这意味着一旦指针指向内存位置,就无法指向另一个位置。
糟糕,不好主意。
此外,行为是特定于平台和实现的。 如果你在一个平台上运行常量存储在不可写内存中,这显然是行不通的。
而且,为什么你想要? 更新源中的常量,或将其设为变量。
此代码包含约束违规 :
const int a = 12; int *p; p = &a;
违反的约束是C11 6.5.16.1/1“简单分配”; 如果两个操作数都是指针,那么左边指向的类型必须具有右边指向的所有类型的限定符。 (并且类型,sans限定符,必须兼容)。
因此违反了约束,因为&a
具有类型const int *
,其中const
为限定符; 但是该限定符没有出现在int *
的类型中。
编译器必须发出诊断信息,并且可能不会生成可执行文件。 任何可执行文件的行为都将完全未定义,因为该程序不符合该语言的规则。
是的,您可以更改常量变量的值。
试试这段代码:
#include int main() { const int x=10; int *p; p=(int*)&x; *p=12; printf("%d",x); }