проблема, связанная с константой и указателями - PullRequest
1 голос
/ 27 января 2012

Я написал 2 программы.Пожалуйста, пройдите обе программы и помогите мне понять, почему переменные 'i' и '* ptr' дают разные значения.

//Program I:
//Assumption: Address of i = 100, address of ptr = 500

int i = 5;
int *ptr = (int *) &i;

*ptr = 99;

cout<<i; // 99
cout<<&i;// 100
cout<<ptr; // 100
cout<<*ptr; // 99
cout<<&ptr; // 500
//END_Program_I===============

//Program II:
//Assumption: Address of i = 100, address of ptr = 500
const int i = 5;
int *ptr = (int *) &i;

*ptr = 99;

cout<<i; // 5
cout<<&i;// 100
cout<<ptr; // 100
cout<<*ptr; // 99
cout<<&ptr; // 500
//END_PROGRAM_II===============

Путаница заключается в том, почему переменная i по-прежнему равна 5, хотя * ptr== 99

Ответы [ 4 ]

6 голосов
/ 27 января 2012

В следующих трех строках вы изменяете константу:

const int i = 5;
int *ptr = (int *) &i;

*ptr = 99;

Это неопределенное поведение.Все может случиться.Так что не делайте этого.


Что касается того, что происходит в этом конкретном случае:

Поскольку i равно constКомпилятор предполагает, что это не изменится.Следовательно, он просто вставляет 5 в каждое место, где он используется.Вот почему распечатка i показывает исходное значение 5.

5 голосов
/ 27 января 2012

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

Хотя это технически идеально, позвольте мне дать вам несколько советов о том, почему это происходит (о«как», см. «Мистический ответ»).

Это происходит потому, что C ++ является по замыслу" несовершенно заданным языком ".«Несовершенство» заключается в ряде «неопределенных поведений», которые пронизывают спецификацию языка.

Фактически, разработчики языка сознательно выбирают, что при некоторых обстоятельствах вместо того, чтобы сказать «если вы это сделаете, вам дадутчто ", (это может быть: у вас есть этот код или у вас есть эта ошибка) они предпочитают говорить" мы не определяем, что произойдет ".

Это позволяет производителям компиляторов свободно решать, что делать.делать.И поскольку на многих платформах работает много компиляторов, может быть оптимальным решением для одного не обязательно оптимальное решение для другого (которое может полагаться на машину с другим набором команд), и, следовательно, вы (как программист) осталисьв драматической ситуации, когда вы никогда не будете знать, чего ожидать, и даже если вы тестируете его, вы не можете доверять результату теста, поскольку в другой ситуации (компиляция того же кода с помощью другого компилятора или просто другой его версии)или для другой платформы) все будет иначе.

«Плохая» вещь в данном случае заключается в том, что компилятор должен предупреждать, когда происходит неопределенное поведение (, заставляяconst следует предупреждать как потенциальную ошибку, особенно, если компилятор выполняет константные оптимизации , так как это бессмыслица, если const разрешено изменять), как это, скорее всего, происходит, есливы указываете правильный флаг (может быть -W4 или -wall или -pedantic или аналогичный, в зависимости от вашего компилятора).

В частности, строка

int *ptr = (int *) &i;

должна выдавать предупреждение вроде: warning: removing cv-qualifier from &i.

, чтобы, если вы исправили свою программу как

const int *ptr = (const int *) &i;

, чтобы удовлетворить предупреждение, вы получите ошибку в

*ptr = 99;

как error: *ptr is const

, что делает проблему очевидной.

Моральstory :

С юридической точки зрения, вы написали плохой код, поскольку он - по определению языка - полагается на неопределенное поведение.

От моральная точка зрения: компилятор вел несправедливое поведение: выполнение константного встраивания (замена cout << i на cout << 5) после принятия (int*)&i является само-противоречием и бессвязнымповедение должно быть, по крайней мере, предупреждено.Если он хочет сделать одну вещь, он не должен принимать другую, или наоборот.

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

2 голосов
/ 27 января 2012
const int i = 5;

Подразумевает, что переменная i является const и не может / не должна быть изменена; она может быть изменяемой; изменение ее с помощью указателя приводит к неопределенному поведению .

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

Запомните правило: Неопределенное поведение - модифицировать переменную const.Никогда не делай этого.

1 голос
/ 27 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...