const在C ++函数体中

时间:2013-09-23 17:25:26

标签: c++ const point-of-interest

我意识到,如果我将const int定义到c ++函数体中然后使用地址算法来改变常量的值(它在堆栈上,不是吗?)。我得到了这段代码:

const int a = 10;
int b = 100;

int * c = &b;
c++;

cout << "&a: " << &a << endl;
cout << " c: " << c << endl;


*c = 100500;

cout << " a: " << a << endl;
cout << "*c: " << *c << endl;

我得到了这个输出

&a: 0x7ffff63866a8
c: 0x7ffff63866a8

 a: 10
*c: 100500

因此,地址是相同的,但值是不同的。有人能解释一下这个结果吗?谢谢! 附:我试过GCC,Clang和VS

6 个答案:

答案 0 :(得分:5)

  

有人能解释一下这个结果吗?

与通过无效指针算法或其他恶作剧以无效方式访问对象的任何尝试一样:未定义的行为。

这里发生的是编译器假设a的值不会发生变化,并将其优化为编译时常量。它被允许这样做,因为你已经宣布它const,从而声明它不会改变。

  

它在堆栈上,不是吗?

由于你也获取它的地址(当你打印&a时),它会在堆栈上分配一个地址;但是,程序不需要从该地址读取以获取值,因为它已经知道为10。

当然,这一切都是未定义的,所以如果它为您订购披萨,该程序将同样有效。

答案 1 :(得分:3)

您的程序在其上面写了未定义的行为......

假设增加b的地址会让你a是假的,它可能或不可能。然后,您使用标准不安全派生指针中调用的内容来修改const对象(a),这也是未定义的行为。任何事情都可能发生。

实际发生的事情(在您的实施中,对结果的解释,但您不能依赖于此,因为这是未定义的行为)是您强制在堆栈中分配a取其地址的方法,你有一个指针。您修改了该值,并更新了内存中的地址。但是,在表达式cout << " a: " << a << endl;中,编译器知道 a是一个常量,因此它的值只能是10,所以它将代码转换为{{1}避免不得不去记忆以获得价值。

答案 2 :(得分:2)

  

它在堆栈上,不是吗?

不,你的期望是错误的。 C ++没有任何堆栈概念,更不用说不同的自动变量如何相对于彼此存储在内存中。你要做的是普通的未定义行为。

在你的情况下,编译器会优化a,因为它们被标准所允许,并且你得到的结果不必有任何意义,因为无论如何它都是UB。

答案 3 :(得分:2)

const int a = 10;
int b = 100;

行。

int * c = &b;

好的,但很傻,我的bug-o-meter开始转动。

c++;

Bug-o-meter现在位于黄色区域。

cout << "&a: " << &a << endl;

*c = 100500;

Bug-o-meter挂钩。调用了未定义的行为。世界爆炸,你被解雇了。

c++将指针移动到内存中的下一个int。指针数学运算正常,但此时您只能使用c来将指针与另一个指针进行比较。您无法以任何方式取消引用指针。但是,当你尝试通过它进行分配时,这就是你所做的。

接下来发生的事情是无关紧要的,老实说,误导。您认为 c现在指向与b相同的内存,也许它确实如此。但只有通过Undefined Behavior才会发生这种情况。您可能认为 *c的值是您所期望的,但此结果为false。也许是,也许不是。当你打开盒子时,你打碎了小瓶 - 猫已经死了。你的计划也是如此。

顺便说一下,如果你想要做的是找到一种方法来欺骗编译器,以便你可以改变const,不要 - 严格禁止更改{{ 1}} 无论如何

C ++中有const,但这也不是可用于更改const_cast的机制。

答案 4 :(得分:0)

C ++编译器将简单地假设您永远不会尝试更改const变量的值。

这并不意味着如果你这样做会导致错误...只是编译器作者可以忽略将要发生的事情,发生的任何事情都会被归类为“你的错”。

答案 5 :(得分:0)

SSCC:

#include <stdio.h>

int main ()
{
  const int a = 10;
  int b = 100;
  int *c = &b;
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  c++;  // "c" now invalid
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  *c = 100500;  // Undefined behavior!
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  return 0;
}

示例输出:

a=10, b=100, *c=100; &a=0028FF18, &b=0028FF14, c=0028FF14
a=10, b=100, *c=10; &a=0028FF18, &b=0028FF14, c=0028FF18
a=10, b=100, *c=100500; &a=0028FF18, &b=0028FF14, c=0028FF18

案例2 - 我们尝试采取CONST的地址A:

#include <stdio.h>

int main ()
{
  const int a = 10;
  int b = 100;
  int *c = &b;
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  c++;  // "c" now invalid
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  *c = 100500;  // Undefined behavior!
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  return 0;
}

示例输出

a=10, b=100, *c=100; &b=0028FF14, c=0028FF14
a=10, b=100, *c=2686744; &b=0028FF14, c=0028FF18
a=10, b=100, *c=0; &b=0028FF14, c=00018894