Можем ли мы изменить значение переменной const?

С в этой статье.

другое использование для объявления переменной как register и const должен препятствовать любому нелокальному изменению этой переменной, даже принимая ее адрес, а затем бросая указатель. Даже если вы думаете, что сами никогда бы этого не сделали, как только вы передадите указатель (даже с атрибутом const) некоторые другие функции, вы никогда не можете быть уверены, что это может изменить переменную под ноги.

Я не понимаю, как мы можем изменить значение const переменной по указателю. Разве это не неопределенное поведение ?

const int a = 81;
int *p = (int *)&a;
*p = 42; /* not allowed */

5 ответов


точки зрения автора заключается в том, что объявление переменной с register класс хранения запрещает Вам принимать его адрес, поэтому он не может быть передан функции, которая может изменить его значение, отбросив const.

void bad_func(const int *p) {
    int *q = (int *) p;            // casting away const
    *q = 42;                       // potential undefined behaviour
}

void my_func() {
    int i = 4;
    const int j = 5;
    register const int k = 6;
    bad_func(&i);                  // ugly but allowed
    bad_func(&j);                  // oops - undefined behaviour invoked
    bad_func(&k);                  // constraint violation; diagnostic required
}

изменяя потенциальный UB в нарушение ограничений, диагностика становится необходимой, и ошибка (должна быть) диагностирована во время компиляции:

c11

5.1.1.3 Диагностика

1 - соответствующая реализация должна произвести, по крайней мере, одно диагностическое сообщение... если ЕП предварительной обработки или преобразования содержит нарушение любого синтаксического правила или ограничения, даже если поведение также явно указывается как неопределенный или определенный реализацией.

6.5.3.2 адреса и косвенного обращения операторов

Ограничения

1 - операнд унарного & оператор должен быть [...] именующее выражение это обозначает объект, который [...] есть объявлен register описатель хранени-класса.

обратите внимание, что распад массива на указатель на register объект массива-это неопределенное поведение, которое не требуется диагностировать (6.3.2.1:3).

обратите внимание также, что принимая адрес register lvalue is разрешено в C++, где register - это просто подсказка оптимизатора (и при этом устаревшая).


можем ли мы изменить значение const переменной?

Да, вы можете изменить const переменная через различные середины: хакеры указателя, бросания ЕТК...
читать следующий Q!!

допустимый ли код для изменения значения const переменной?

нет! Что это дает вам Неопределенное Поведение.

Techniclally, код пример имеет Неопределенное Поведение.
Программа не придерживается стандарта c после изменения const и, следовательно, может дать любой результат.

обратите внимание, что неопределенное поведение не означает, что компилятор должен сообщить о нарушении в качестве диагностики. В этом случае ваш код использует pointer hackery для изменения const и компилятор не нужен для обеспечения диагностики для него.

на стандарт C99 3.4.3 говорит:

неопределенное поведение: поведение при использовании непортящейся или ошибочной конструкции программы или ошибочных данных, к которым настоящий международный стандарт не предъявляет никаких требований.

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


ваш код компилируется, но он имеет неопределенное поведение.

точка зрения автора заключается в использовании const и register чтобы код больше не компилировался:

const int a = 81; 
int *p = (int *)&a; /* no compile error */
*p = 42; /* UB */ 

register const int b = 81; 
int *q = (int *)&b; /* does not compile */

фрагмент кода действительно вызывает неопределенное поведение.

Я не совсем уверен, что точка зрения автора: чтобы не позволить "иностранному коду" изменить значение переменной, вы делаете это const Так что... Вместо этого вызывается UB? Как это предпочтительнее? Честно говоря, это не имеет смысла.


Я думаю, что автор также говорит об этом случае, что является непониманием const:

 int a = 1;
 int* const a_ptr = (int* const)&a; //cast not relevant
 int function(int* const p){
     int* malicious = (int*)p;
     *malicious = 2;
 }

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