Я не уверен, что стандарты C / C ++ обозначают строки.Но я могу сказать точно , что на самом деле происходит со строковыми литералами в MSVC.И, я полагаю, другие компиляторы ведут себя аналогично.
Строковые литералы находятся в разделе данных const.Их память отображается в адресном пространстве процесса.Однако страницы памяти, в которых они хранятся, предназначены только для чтения (если явно не изменены во время выполнения).
Но есть кое-что еще, что вы должны знать.Не все выражения C / C ++, содержащие кавычки, имеют одинаковое значение.Давайте все проясним.
const char* a = "test";
Вышеприведенный оператор заставляет компилятор создавать строковый литерал "test".Компоновщик гарантирует, что он будет в исполняемом файле.В теле функции компилятор генерирует код, который объявляет переменную a
в стеке, которая инициализируется адресом строкового литерала "test.
char* b = a;
Здесь вы объявляете другую переменную b
в стеке, который получает значение a
. Поскольку a
указывает на адрес только для чтения - то же самое можно сказать и о b
. Четный факт b
не имеет семантики const
, не означает, что вы можете изменить то, чтоон указывает на
char *c = "test"; // no compile errors
c[0] = 'p';
Вышеуказанное приводит к нарушению доступа. Опять же, отсутствие const
ничего не значит на уровне машины
const char d = 'a';
*(char*)&d = 'b';
Прежде всего -вышеприведенное не относится к строковым литералам. 'a' - это не строка. Это символ. Это просто число. Это похоже на написание следующего:
const int d = 55;
*(int*)&d = 56;
Приведенный выше код делает дурака из компилятораВы говорите, что переменная const
, однако вам удается ее изменить. Но это не связано с исключением процессора, поскольку, тем не менее, d
находится в памяти для чтения / записи.
Я бы хотелдобавить один разe case:
char b[] = "test";
b[2] = 'o';
Выше объявляется массив в стеке и инициализируется со строкой "test".Он находится в памяти для чтения / записи и может быть изменен.Здесь нет проблем.