char *msgs[]={"123"}; // указатель на массив КОНСТАНТНЫХ строк
являются КОНСТАНТНЫМИ стоками
ведь компиляторы не ругаются
и даже в некоторых случаях все работает:
BC31 — выдает рабочую прогу
VC6 — release-работает, debug-нет
gcc — нет
W>вылетает в строке: W>pc[0]='0';
W>кто может объяснить в чем некорректность?
Некореректность в том, что за счет стандартного преобразования (4.2/2) в msgs[0] лежит неконстантный указатель на литерал "123". Последующая попытка модификации этого литерала есть не что иное, как неопределенное поведение. В твоем случае получился вылет, а могло быть и хуже
Здравствуйте, Bell, Вы писали:
B>Некореректность в том, что за счет стандартного преобразования (4.2/2)
Не понял, что такое: "преобразование (4.2/2)"
можно по подробнее
Здравствуйте, winogr, Вы писали:
W>Не понял, что такое: "преобразование (4.2/2)"
Преобразование, описаное в стандарте языка C++, в пункте 4.2, раздел 2.
W>можно по подробнее
Конечно:
4.2 Array-to-pointer conversion
...
2 A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”;
...
Это означает ссылку на Стандарт языка С++ ANSI/ISO 14882-2003, пункт 4.2, clause 2, который гласит:
[conv.array] 4.2 Array-to-pointer conversion
........
2 A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to
char”; ........
Здравствуйте, Bell, Вы писали:
B>Некореректность в том, что за счет стандартного преобразования (4.2/2) B>в msgs[0] лежит неконстантный указатель на литерал "123".
правильнее наверное было бы получить константный указатель
но и не константный указатель это нормально.
B>Последующая попытка модификации этого литерала есть не что иное, как неопределенное поведение.
Но почему вдруг нельзя модифицировать литерал
я всегда считал что литерал это не константа
Здравствуйте, winogr, Вы писали:
B>>Некореректность в том, что за счет стандартного преобразования (4.2/2) B>>в msgs[0] лежит неконстантный указатель на литерал "123". W>правильнее наверное было бы получить константный указатель
Да, наверное. W>но и не константный указатель это нормально.
Насколько это нормально — видно из исходного вопроса. ИМХО конечно.
B>>Последующая попытка модификации этого литерала есть не что иное, как неопределенное поведение. W>Но почему вдруг нельзя модифицировать литерал W>я всегда считал что литерал это не константа
Это неправильно.
2.13.4/1
A string literal is a sequence of characters (as defined in 2.13.2) surrounded by double quotes, optionally
beginning with the letter L, as in "..." or L"...". A string literal that does not begin with L is an ordinary
string literal, also referred to as a narrow string literal. An ordinary string literal has type “array of n
const char” and static storage duration (3.7), where n is the size of the string as defined below, and is
initialized with the given characters.
...
Здравствуйте, Bell, Вы писали:
B>>>Последующая попытка модификации этого литерала есть не что иное, как неопределенное поведение. W>>Но почему вдруг нельзя модифицировать литерал W>>я всегда считал что литерал это не константа B>Это неправильно.
B>
B>2.13.4/1
B>A string literal is a sequence of characters (as defined in 2.13.2) surrounded by double quotes, optionally
B>beginning with the letter L, as in "..." or L"...". A string literal that does not begin with L is an ordinary
B>string literal, also referred to as a narrow string literal. An ordinary string literal has type “array of n
B>const char” and static storage duration (3.7), where n is the size of the string as defined below, and is
B>initialized with the given characters.
B>...
Спасибо.
Но к сожалению этот стандарт описывает не совсем тот язык "C" к которому я привык.
Придется переучиваться.
Re[7]: Инициализация массива строк
От:
Аноним
Дата:
10.03.09 11:38
Оценка:
Здравствуйте, winogr, Вы писали:
W>Спасибо. W>Но к сожалению этот стандарт описывает не совсем тот язык "C" к которому я привык.
скорее похоже, что вы привыкли к не совсем тому языку С++
или, что более похоже, к не совсем тем компиляторам, которые не совсем соответствуют стандарту
Здравствуйте, Vlad_SP, Вы писали:
V_S>Это означает ссылку на Стандарт языка С++ ANSI/ISO 14882-2003, пункт 4.2, clause 2, который гласит:
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, winogr, Вы писали:
W>кто может объяснить в чем некорректность?
А тебе какой из двух языков? Может ты С, как С++ компилируешь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, winogr, Вы писали:
W>Есть код:
W>кто может объяснить в чем некорректность?
Засыпали бедного парня цитатами из стандарта. Объяснить все надо проще, имхо.
Итак, что написано в строке:
char * p = "ABC";
Там написано, что компилятор в области статических данных( read only memory ) помещает строку "ABC". Указатель p на char хранит в себе значение адреса ячейки памяти, где расположен символ "A"
Теперь попробуем
p[0] = 'D';
Мы пытаемся записать по этому адресу другое значение. Но доступа на запись у нас туда нет — Visual Studio говорит на это четко: 0xC0000005: Access violation writing location 0x0040313c.!
( с массивами строк — аналогично ).
Работающий код выглядить должен как-то так:
char * p = new char[4];
strcpy( p, "ABC\0" );
p[0]='D';
или так:
char m[] = "ABC";
char * p = m;
p[0] = 'D';
В обоих примерах p теперь указывает на область памяти, которую можно модифицировать!
Так что различие-то не не в константах и литералах, а в памяти и указателях.
A>Там написано, что компилятор в области статических данных( read only memory ) помещает строку "ABC". Указатель p на char хранит в себе значение адреса ячейки памяти, где расположен символ "A" A>Теперь попробуем
А почему область статических данных обязательно read only memory?
Скажем такой вот код:
int a1 = 5;
int a2 = a1 *= 2;
Вполне так себе порождает модифицируемые статические данные...
Возможно меня глючит, но мне кажется, что в языке С строковые литералы модифицируемые, а в С++ нет. Я так подозреваю, что у топикстартера язык С, а компилятор почему-то берётся С++, от того все и проблемы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ariets, Вы писали:
A>Засыпали бедного парня цитатами из стандарта. Объяснить все надо проще, имхо.
Действительно. Проще всего так: вообще-то implicit конвертирование const в не-const не должно быть позволено, мы имеем дело с очередной нелогичностью языка C++, которых там еще много-много-много, так что придется привыкать.
A>Так что различие-то не не в константах и литералах, а в памяти и указателях.
В специфике операционной системы, если быть точнее. Если предварительно сменить защиту памяти на секции константных данных, то можно будет спокойно писать туда без access violation.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, ariets, Вы писали:
A>>
A>>char * p = "ABC";
A>>
A>>Там написано, что компилятор в области статических данных( read only memory ) помещает строку "ABC". Указатель p на char хранит в себе значение адреса ячейки памяти, где расположен символ "A" A>>Теперь попробуем
E>А почему область статических данных обязательно read only memory?
E>Скажем такой вот код:
E>int a1 = 5;
E>int a2 = a1 *= 2;
Вообще-то в скобках я уточнил, какие именно статические данные для строковой константы — read only. Я не имел ввиду, что все статические данные — read only.
Перефразирую: "Там написано, что компилятор в секции константных данных( read only memory ) помещает строку "ABC"
Здравствуйте, ariets, Вы писали:
A>Перефразирую: "Там написано, что компилятор в секции константных данных( read only memory ) помещает строку "ABC"
А разве там это написано? Вроде как с С литералы не константны...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
A>>Перефразирую: "Там написано, что компилятор в секции константных данных( read only memory ) помещает строку "ABC"
E>А разве там это написано? Вроде как с С литералы не константны...
В С строковые литералы не константны по типу (т.е. в C это 'array of char' а не 'array of const char'). Тем не менее и в С модификация строкового литерала запрещена, т.е. четко сказано, что попытка модификации строкового литерала приводит к неопределенному поведению.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, ariets, Вы писали:
A>>Перефразирую: "Там написано, что компилятор в секции константных данных( read only memory ) помещает строку "ABC"
E>А разве там это написано? Вроде как с С литералы не константны...
Поподробнее про память, чтобы точно объяснить почему все так происходит.
Есть строка. Она хранится в памяти. Область памяти называется "Константные данные"(Const Data). То, что туда нельзя писать, говорит сам компилятор VS( говорят, правда, что можно настроить, чтобы запись туда была разрешена, но вопрос форума — объяснить, почему вылетает прога )
По поводу области памяти: их вообще 5 — константные данные, стек, свободная динамическая память, куча, глобальная/статическая.
Константные данные: в этой области хранятся строки и другие данные, чьи значения известны во время компиляции. В этой области не могут находиться объекты классов.Все данные из этой области доступны в течение всего времени жизни программы. Кроме того, все данные в этой области памяти доступны только для чтения, и результат попытки их изменения не определен. В частности, это связано с тем, что формат хранения этих данных может быть оптимизирован конкретной реализацией языка. Например, компилятор может оптимизировать хранение строк и разместить их в перекрывающихся объектах. Это объясняет, почему разные компиляторы дают разные результаты.