#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Будет ли это работать?
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Будет ли это работать?
Это "undefined поведение", что означает, что на основе стандарта вы не можете предсказать, что произойдет, когда вы попробуете это. Он может делать разные вещи в зависимости от конкретной машины, компилятора и состояния программы.
В этом случае наиболее часто случается, что ответ будет "да". Переменная const или нет - это просто место в памяти, и вы можете нарушать правила константы и просто перезаписывать ее. (Конечно, это вызовет серьезную ошибку, если какая-либо другая часть программы зависит от постоянных константных данных!)
Однако в некоторых случаях - наиболее типично для данных const static
- компилятор может помещать такие переменные в область памяти только для чтения. Например, MSVC обычно ставит константные статические ints в сегменте .text исполняемого файла, что означает, что операционная система будет вызывать ошибку защиты, если вы попытаетесь записать на нее, и программа выйдет из строя.
В какой-то другой комбинации компилятора и машины может произойти нечто совершенно другое. Единственное, что вы можете точно предсказать, это то, что этот шаблон будет раздражать тех, кто должен прочитать ваш код.
Это поведение undefined. Доказательство:
/* 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 в регистр и не утруждает себя повторной загрузкой, когда ему нужно получить доступ к a для printf, потому что он "знает", что не может измениться.
Изменение квалифицированного объекта const
через указатель вызывает неопределенное поведение, и таков результат. Это может быть то, что вы ожидаете от конкретной реализации, например, предыдущее значение без изменений, если оно было помещено в .text
и т.д.
Это действительно работает с gcc. Это ему не понравилось, хотя:
test.c: 6: warning: присваивание отбрасывает квалификаторы из целевого типа указателя
Но значение изменилось при выполнении. Я не буду указывать на очевидное нет-нет...
да, вы можете сделать это, используя такой код. но код не применяется, когда 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
. Это означает, что, как только указатель указывает на ячейку памяти, вы не можете указать ее на другое местоположение.
Плохая идея BAD.
Кроме того, поведение зависит от платформы и реализации. Если вы работаете на платформе, где константа хранится в незаписываемой памяти, это явно не сработает.
И, зачем же вы хотите? Либо обновите константу в своем источнике, либо сделайте ее переменной.
Этот код содержит нарушение ограничений:
const int a = 12;
int *p;
p = &a;
Нарушением является C11 6.5.16.1/1 "Простое присвоение"; если оба операнда являются указателями, то тип, на который указывает левый, должен иметь все определители типа, на который указывает справа. (И типы, не имеющие квалификаторов, должны быть совместимы).
Таким образом, ограничение нарушается, потому что &a
имеет тип const int *
, который имеет const
как квалификатор; но этот определитель не отображается в типе p
который является int *
.
Компилятор должен испускать диагностику и не может генерировать исполняемый файл. Поведение любого исполняемого файла полностью не определено, так как программа не соответствует правилам языка.
Да, вы можете изменить значение постоянной переменной.
Попробуйте этот код:
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}