2014-02-03 2 views
0

Я знаю, что в C мы можем изменить «const int» с помощью указателя. Но при компиляции программы я включил флаг «-O2» в gcc и const int не смог изменить значение, поэтому просто хотел знать, как флаг оптимизации gcc влияет на модификацию «const int».gcc -O2 влияют на изменения при изменении const int

Вот пример приложения test.c

#include <stdio.h> 
#include <stdlib.h> 

int main(int ac, char *av[]) 
{ 
     const int i = 888; 
     printf("i is %d \n", i); 
     int *iPtr = &i; 
     *iPtr = 100; 
     printf("i is %d \n", i); 
     return 0; 
} 

gcc -Wall -g -o test test.c 
./test 
i is 888 
i is 100 

gcc -Wall -g -O2 -o test test.c 
i is 888 
i is 888 

Это любопытство заставляет меня написать этот вопрос.

+2

Я получаю предупреждение. 'initialization отбрасывает 'const' классификатор от типа целевого указателя'. –

+0

«Я знаю, что в C мы можем изменить« const int »с помощью указателя« Извините? –

ответ

1

Неопределенное поведение для изменения переменной, объявленной как const. Неопределенное поведение ... undefined; другими словами, компилятор может сделать что-либо , включая, предполагая, что неопределенное поведение на самом деле не происходит.

В этом случае компилятор может оптимизировать доступ к const int i, предположив, что он никогда не изменяется; что позволяет компилятору вставить известное начальное значение i при вызове printf. Фактически, он мог бы прекомпопировать строку, которая будет выводиться во время компиляции, так как она знает, что должно делать printf.

Неверно, что вы можете обходить const декларациями через указатели. Если переменная изначально объявлена ​​как const, попытки ее изменения недействительны. Что вы можете сделать, так это создать указатель const изменчивой переменной, а затем обойти const смысл указателя, отбросив его. Поскольку исходная переменная не является const, это является законным (хотя обычно это не очень хорошая идея.)

(Обязательная стандартная ссылка: § 6.7.3/6: «Если делается попытка изменить объект, определенный с помощью константы -qualified, используя значение lvalue с неконстанционно-квалификационным типом, поведение не определено. ")

1

Я знаю, что в C мы можем изменить 'const int' с помощью указателя.

Нет, это неправильно. В стандарте языка C четко говорится, что изменение объекта const - это «неопределенное поведение». Это означает, что что-то вообще может произойти - код может преуспеть, он может упасть, он может повредить ваш жесткий диск или заставить демонов вылететь из вашего носа. Все эти виды поведения считаются законными. Таким образом, тот факт, что поведение изменяется в зависимости от уровня оптимизации компилятора, также совершенно легально.

Любой компилятор, достойный его соли, предупредит вас об этом. С по умолчанию опции компилятора, GCC услужливо говорит мне об этом, когда я пытаюсь скомпилировать код:

$ gcc test.c 
test.c: In function 'main': 
test.c:8:21: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] 

Clang похож:

$ clang test.c 
test.c:8:14: warning: initializing 'int *' with an expression of type 
     'const int *' discards qualifiers 
     [-Wincompatible-pointer-types-discards-qualifiers] 
     int *iPtr = &i; 
      ^ ~~ 
+0

Да, это также дает мне предупреждение, но я могу получить значение, но когда я добавляю флаг оптимизации, значение не может измениться. Ранее я прочитал вопрос http://stackoverflow.com/questions/945640/constants-and-pointers-in-c/945660, и я понимаю поведение константы в c, но не могу понять поведение с флагом оптимизации , – skanzariya

+1

@skanzariya - вы, вероятно, не видите каких-либо результатов модификации из-за [постоянного распространения] (http://en.wikipedia.org/wiki/Constant_folding) при оптимизации. Но трудно объяснить поведение, которое явно * undefined *. –

+0

Привет @Brett, спасибо за выписывание, Да, трудно понять неопределенное поведение, я знал о «const», но хотел понять немного в глубину. Благодарю. – skanzariya

0

Эта линия является нарушением ограничения:

int *iPtr = &i; 

Тип &i: const int *. Поведение кода описано в разделе 6.5.16.1/1 текущего стандарта C («Простое присваивание»), в котором перечислены ограничения на назначение.

Часть этих ограничений состоит в том, что для левого операнда НЕ является указателем на неквалифицированный тип, в то время как правый операнд является указателем на квалифицированный тип.

Если компилятор работает в стандартном режиме, он должен предоставить диагностическое сообщение. Он может не сгенерировать исполняемый файл. Если компилятор действительно делает что-то еще, тогда поведение больше не распространяется на Стандарт. (Другими словами, программа имеет полное неопределенное поведение).

NB. В других ответах упоминается «изменение объекта const», однако это не имеет значения, поскольку нарушение ограничения происходит до попытки изменения объекта; и все ставки отключены после нарушения ограничения.

Смежные вопросы