2013-09-23 1 views
-5

Я понял, что если я определяю const int в тело функции C++, а затем используйте арифметику адреса, чтобы изменить значение константы (ее в стеке, не так ли?). я получил этот код:const в теле функций 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

+1

Изменение константы anyways - это неопределенное поведение в стандартах. –

+0

Вы только что вызвали неопределенное поведение. –

+0

Значение 'c' post-increment не определено поведением, ни по значению, ни по разыменованию. Если бы 'b' был массив (даже массив из одного), значение было бы определено, но разыменование все равно не было (в случае с одной длиной). – WhozCraig

ответ

2
const int a = 10; 
int b = 100; 

ОК.

int * c = &b; 

ОК, но глупо и мой баг-о-метр начинает крутить.

c++; 

Ошибка-o-meter теперь в желтой зоне.

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

OK

*c = 100500; 

Bug-о-метр привязанный. Вызывается не определено поведение. Мир взрывается, вас увольняют.

c++ перемещает указатель на следующий int в память. Математика указателя в порядке, но все, что вы можете использовать c, на данный момент - сравнить указатель с другим указателем. Вы никак не можете разыменовать указатель. Но это то, что вы делаете, когда пытаетесь назначить через него.

Что происходит дальше, не имеет значения и, честно говоря, вводит в заблуждение. Вы думаете, что c теперь указывает на ту же память, что и b, и, может быть, так и есть. Но это произошло только через Undefined Behavior. Вы могли бы также подумать, что значение *c - это то, что вы ожидаете от него, но этот результат является ложным. Возможно, это возможно, возможно, это не так. Вы разорвали флакон, когда вы открыли коробку - кошка мертва. И ваша программа тоже.

И, кстати, если то, что вы пытаетесь сделать, это найти способ обмануть компилятор, так что вы можете изменить const, нет - это строго запрещено менять constлюбыми средствами.

В C++ есть const_cast, но это также не механизм, который вы можете использовать для изменения const.

2

его на стеке, не так ли?

Нет, ваши ожидания неверны. C++ не имеет понятия стека вообще, а тем более от того, как разные автоматические переменные хранятся в памяти относительно друг друга. То, что вы пытаетесь сделать, - это просто неопределенное поведение.

В вашем случае компиляторы оптимизируют a, потому что им разрешен стандарт, а полученные вами результаты не имеют никакого смысла, так как это UB в любом случае.

5

Может ли кто-нибудь объяснить мне этот результат?

Как с любой попыткой получить доступ к объектам недействительными способами с помощью недействительной арифметики указателя или других параметров shenanigans: undefined.

Что здесь происходит, так это то, что компилятор предполагает, что значение a не изменится и оптимизирует его как константу времени компиляции. Это разрешено, так как вы объявили его const и тем самым заявили, что он не изменится.

его на стек, не так ли?

Поскольку вы также берете его адрес (при печати &a), он получает выделенный адрес в стеке; но нет необходимости, чтобы программа читала с этого адреса, чтобы получить значение, так как уже известно, что оно равно 10.

Конечно, это все не определено, поэтому программа была бы столь же действительной, если бы она заказала вам вместо пиццы.

+0

Абсолютно правильно. Два ключевых момента: 1) значение «const» делает * NOT * необходимо хранить в стеке: компилятор может делать с ним все, что захочет, 2) «неопределенное поведение» == «так же справедливо, если он приказал вам вместо этого пицца ". Отличный ответ :) – paulsm4

+0

+1 за «приказали тебе пиццу» ... Я хочу моего с пепперони! –

0

Компилятор C++ просто предположит, что вы никогда не попытаетесь изменить значение переменной const.

Это не значит, что если вы это сделаете, вы получите сообщение об ошибке ... просто, что авторы компилятора могут игнорировать то, что произойдет, и все, что происходит, будет классифицироваться как «ваша ошибка».

3

Ваша программа имеет неопределенное поведение написано над ним ...

Предположение о том, что увеличивающиеся адрес из b приведет вас к a является поддельным, он мог или не мог. Затем вы используете то, что вызывается в стандартном unsafely производном указателе, чтобы изменить объект const (a), который также является неопределенным поведением. Все может случиться.

Что действительно происходит (в вашей реализации, объяснение ваших результатов, но вы не можете зависеть от этого, поскольку это неопределенное поведение) является то, что вы заставили распределение a в стеке путем принятия его адрес, и вы получил указатель на него. Вы изменили это значение и обновили адрес в памяти. Но в выражении: cout << " a: " << a << endl; компилятор знает, что a является константой, поэтому ее значение может быть только 10, поэтому оно преобразует код в cout << " a: " << 10 << endl;, чтобы избежать необходимости переходить в память для получения значения.

0

СПССК:

#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 - МЫ НЕ попытаться принять AddressOf 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 
+0

Вы вызывали «неопределенное поведение!». на второй printf ... –