Ошибка в компиляторе Visual Studio C ++? - PullRequest
2 голосов
/ 23 февраля 2009

Этот код ведет себя странно в MS Visual Studio:

char *s = "hello";
s[0] = 'a';
printf(s); 

В сборке релиза с включенной оптимизацией игнорируется s [0] = 'a' и выводится "привет". Без оптимизации или в отладочной сборке происходит сбой с нарушением прав доступа.
Это поведение соответствует стандарту c ++ или нет? На мой взгляд, компилятор должен разрешать только постоянные ссылки на строковые литералы, т.е.

const char *s = "hello";

РЕДАКТИРОВАТЬ : Я знаю, почему это так работает, я не понимаю, почему мне разрешено делать неконстантные ссылки только для чтения.

Ответы [ 6 ]

14 голосов
/ 23 февраля 2009

Нет, это не ошибка в компиляторе. Когда вы пишете:

char* s = "hello";

Строковая константа "hello" будет помещена в раздел только для чтения и должна генерировать исключение, если вы попытаетесь ее изменить. (исключение ОС, не исключение C ++).

Чтобы сделать его доступным для записи, вы должны либо использовать массив:

char s[] = { 'h', 'e', 'l', 'l', 'o', 0 };

или, если вам действительно нужен указатель, сделайте так, чтобы он указывал на массив:

char _s[] = { 'h', 'e', 'l', 'l', 'o', 0 };
char* s = _s;

Я понимаю, что вы хотите разрешить инициализацию только указателей const с помощью строковых литералов, но я думаю, что это нарушит lot существующего кода.

7 голосов
/ 23 февраля 2009

Причина, по которой этот код разрешен в первую очередь (вместо того, чтобы требовать декларации типа char const*), заключается в обратной совместимости со старым кодом C.

Большинство современных компиляторов в строгом режиме выдают предупреждение для приведенного выше кода, хотя!

3 голосов
/ 23 февраля 2009

Я думаю, что компиляторам C ++ разрешено размещать строковые литералы в страницах памяти только для чтения в соответствии со стандартом.

2 голосов
/ 23 февраля 2009

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

Я на самом деле немного удивлен, что вы не получите нарушения прав доступа, когда оно скомпилировано с оптимизацией.

1 голос
/ 23 февраля 2009
char *s = "foo";

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

char *t = "foo";

Теперь компилятор, в лучшем случае, сохранит только одну копию, а ее изменение будет означать лот работы только для того, чтобы вы и ваш друг были счастливы. Так что он не пытается это сделать. Это то, что вы должны найти в стандарте. Угадай, что, что ты делаешь, вызывает UB.

Тем не менее, если бы у вас был свой путь, это сломало бы много унаследованного кода, который бедные парни из Комитета по стандартам не могли себе позволить. Итак, вы здесь.

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

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

0 голосов
/ 23 февраля 2009

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

...