2013-12-21 2 views
-2

Как известно, значение постоянной переменной является неизменным. Но мы можем использовать указатель постоянной переменной для его изменения.Являются ли константные идентификаторы обработаны по-разному в C++?

#include <iostream> 

int main() 
{ 
    const int integer = 2; 
    void* tmp = (void*)&integer; 
    int* pointer = (int*)tmp; 

    (*pointer)++; 

    std::cout << *pointer << std::endl; 
    std::cout << integer << std::endl; 

    return 0; 
} 

выход этого кода:

3 
2 

Итак, я запутанным, что я модифицирована на земле? что делает integer подставка?

+0

Да, если вы хотите достаточно хорошо стрелять в ногу, вы можете найти способ. – meagar

+0

Я помню, что когда я это сделал (как в Delphi, так и в C), я получил «нарушение доступа». Возможно, ПК сможет проверять доступ во время выполнения, но ваша платформа отличается. – Val

+0

Шаг указателя пустоты не нужен. И никто не упоминал о неопределенном поведении, поэтому обратите внимание, что UB - это то, что есть. – chris

ответ

4

Изменение const s не определено. Компилятор может хранить значения const только в частях памяти только для чтения и бросать ошибку, когда вы пытаетесь их изменить (бесплатно, а не обязано). Неопределенное поведение плохое, нежелательное и его следует избегать. Таким образом, не делайте этого.

PS integer и pointer - это имена переменных в вашем коде, которые не являются особенно хорошими именами.

3

Вы использовали небезопасные броски C-стиля, чтобы выбросить консистенцию. C++ не является неотъемлемо безопасным языком, поэтому вы можете делать такие сумасшедшие вещи. Это не значит, что вам нужно. Фактически, вы не должны использовать C-стиль приведения в C++ вообще - вместо этого используйте reinterpret_cast, const_cast, static_cast и dynamic_cast. Если вы это сделаете, вы обнаружите, что способ изменить значения const - это использовать const_cast, который точно соответствует языку.

+0

Неправильно. 'const_cast' позволяет вам изменять ** неконстантные ** объекты, но это позволяет вам сделать это через выражение const. – MSalters

-1

Ключевое слово const является лишь подсказкой для компилятора. Компилятор проверяет, является ли переменная константой или нет, и если вы изменяете переменную const напрямую, компилятор дает вам неправильную информацию. Но для защиты константных переменных нет механизма хранения переменных. Поэтому операционная система не может знать, какая переменная const или нет.

+0

см. Ответ Ричарда Плюнкетта. – Jarod42

+0

Любой современный процессор имеет такой механизм. Используется ли это для компилятора, но страницы, доступные только для чтения, довольно распространены. – MSalters

0

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

Когда вы объявляете integer как константу и используете ее в выражении, оптимизируете компилятор и заменяете его постоянным литералом, который вы ему назначили. Но фактическое содержимое ячейки памяти, на которое указывает &integer, изменено. Компилятор просто игнорирует этот факт, потому что вы определили его как константу.

См. Const Correctness in C++. Обратите внимание на вывод ассемблера чуть выше раздела «Оператор Const_cast» на этой странице.

0

Вы пробираетесь в территорию неопределенного поведения.

Если вы пишете

void* tmp = &integer; 

компилятор даст вам ошибку. Если вы написали хороший код на C++ и написали

void* tmp = static_cast<void*>(&integer); 

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

Есть несколько способов, компилятор мог бы иметь дело с этим, не в последнюю очередь из которых:

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

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

Рассмотрим

const char h = 'h'; 
    const char* hello = "hello"; 
    const unsigned char num = 2 * 50 + 2 * 2; // 104 == 'h' 
    arg -= num; // sub 104, eax 

    char* ptr = (char*)(&h); 

Компилятор может выбрать для хранения «ч» специально с целью «PTR», или он может выбрать, чтобы сделать «PTR» указывают на «ч» в привет. Или он может выбрать местоположение местоположения значения 104 в команде «sub 104, eax».

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