Я что-то упустил? С каких пор на литерную строку можно брать неконстантный указатель? Код (Text): char* str = "string"; http://www.comeaucomputing.com/tryitout/
_DEN_ Что-то странное с этим. VS 2003 такое компилит: Код (Text): #include <iostream> void foo() { char* str = "string_abcdef"; std::cout<<str<<std::endl; } int main(int argc, char* argv[]) { char* str = "string_abcdef"; str[0] = '1'; foo(); } Но на строке str[0] = '1'; получаем access violation. Посмотрел в ольке. Оказалось что оба указателя указывают на адрес в секции rdata, которая с правами read. ^) VS 2005 тоже валиться. ^) P.S Вобщем присвоили константную строку указателю на не константу, и сидим довольные. А компилятору на это до лампочки.
Booster Майкрософтовские компиляторы, как впрочем и все остальные, никогда не были показателями качества с точки зрения стандарта. Проверка чего-либо на VS 200X - это как анекдот про Мойше и Beatles. Только Comeau имеет репутацию компилятора, практически на 100% следующего Стандарту. Если я все правильно помню, то еще совсем недавно Comeau эту конструкцию не компилировал, ругаясь на то, что "Cannot convert const char[6] to char*"
Booster Comeau это не тот компилятор, который пойдет на отступление от Стандарта, ради какой-то там совместимости Кроме того, такая совместимость, по мимо нарушения Стандарта, просто не имеет смысла, по скольку у каждого уважающего себя компилятора есть два отдельных режима: Compite as C и Compile as C++. Как вариант, ни студия, ни камю не будут компилировать по правилам C++ например вот такую конструкцию Код (Text): void foo(int const n) { char array[n]; } несмотря на то, что это законный C99
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86 Код (Text): char* foo() { char* str = "string_abcdef"; str[1] = '2'; return str; } int main(int argc, char* argv[]) { char* str = "string_abcdef"; str[0] = '1'; return (int)foo()[1]; } Выдаёт Код (Text): ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.346 TITLE C:\WINDOWS\Temp\CL\x32\1.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG607 DB 'string_abcdef', 00H ORG $+2 $SG615 DB 'string_abcdef', 00H _DATA ENDS PUBLIC _foo ; Function compile flags: /Odtp _TEXT SEGMENT _str$ = -4 ; size = 4 _foo PROC ; File c:\windows\temp\cl\x32\1.c ; Line 2 push ebp mov ebp, esp push ecx ; Line 3 mov DWORD PTR _str$[ebp], OFFSET $SG607 ; Line 4 mov eax, DWORD PTR _str$[ebp] mov BYTE PTR [eax+1], 50 ; 00000032H ; Line 5 mov eax, DWORD PTR _str$[ebp] ; Line 6 mov esp, ebp pop ebp ret 0 _foo ENDP _TEXT ENDS PUBLIC _main ; Function compile flags: /Odtp _TEXT SEGMENT _str$ = -4 ; size = 4 _argc$ = 8 ; size = 4 _argv$ = 12 ; size = 4 _main PROC ; Line 9 push ebp mov ebp, esp push ecx ; Line 10 mov DWORD PTR _str$[ebp], OFFSET $SG615 ; Line 11 mov eax, DWORD PTR _str$[ebp] mov BYTE PTR [eax], 49 ; 00000031H ; Line 12 call _foo movsx eax, BYTE PTR [eax+1] ; Line 13 mov esp, ebp pop ebp ret 0 _main ENDP _TEXT ENDS END Т.е. кладёт в RW секцию данных. Microsoft (R) C/C++ Optimizing Compiler Version 14.00.50727.762 for x64 выдаёт: Код (Text): ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.346 include listing.inc INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG536 DB 'string_abcdef', 00H ORG $+2 $SG544 DB 'string_abcdef', 00H _DATA ENDS PUBLIC foo pdata SEGMENT $pdata$foo DD imagerel $LN3 DD imagerel $LN3+32 DD imagerel $unwind$foo pdata ENDS xdata SEGMENT $unwind$foo DD 010401H DD 02204H ; Function compile flags: /Odtp xdata ENDS _TEXT SEGMENT str$ = 0 foo PROC ; File c:\windows\temp\cl\x64\1_64.c ; Line 2 $LN3: sub rsp, 24 ; Line 3 lea rax, OFFSET FLAT:$SG536 mov QWORD PTR str$[rsp], rax ; Line 4 mov rax, QWORD PTR str$[rsp] mov BYTE PTR [rax+1], 50 ; 00000032H ; Line 5 mov rax, QWORD PTR str$[rsp] ; Line 6 add rsp, 24 ret 0 foo ENDP _TEXT ENDS PUBLIC main pdata SEGMENT $pdata$main DD imagerel $LN3 DD imagerel $LN3+47 DD imagerel $unwind$main pdata ENDS xdata SEGMENT $unwind$main DD 010d01H DD 0620dH ; Function compile flags: /Odtp xdata ENDS _TEXT SEGMENT str$ = 32 argc$ = 64 argv$ = 72 main PROC ; Line 9 $LN3: mov QWORD PTR [rsp+16], rdx mov DWORD PTR [rsp+8], ecx sub rsp, 56 ; 00000038H ; Line 10 lea rax, OFFSET FLAT:$SG544 mov QWORD PTR str$[rsp], rax ; Line 11 mov rax, QWORD PTR str$[rsp] mov BYTE PTR [rax], 49 ; 00000031H ; Line 12 call foo movsx eax, BYTE PTR [rax+1] ; Line 13 add rsp, 56 ; 00000038H ret 0 main ENDP _TEXT ENDS END Что тоже в RW. Пример бажный заведомо, т.к. некоторые компилеры кладут локальные строки на стэк, но это не суть. Можно проследитЬ, что указатель хранится как указатель, т.е. в памяти при некоторых компилерах и при явном указании static в случае CL. Обе программы исполняются верно, не вызывая исключений. Так и не удалось заставить CL засунуть саму строку в секцию R-only при использовании указателей. Зато работает как надо для строк вида const str[]=... причём при таком раскладе как правило никода сам указатель нигде не хранится, а используется непосредственно адрес строки.
asmfan Это все безумно интересно, но меня волнует несколько другое Почему Comeau это компилирует? У меня помутнение памяти и это компилилось всегда? Или же что-то случилось с Comeau? Или поменяли Стандарт? На сколько я помню, все литерные значения всегда трактовались как const.
_DEN_ Я имел ввиду то, что вполне возможно это есть стандарт С++, в целях совместимости с Си. Ведь в С++ много такого барахла. У комею тоже всякие деприкейтед опции есть.
_DEN_ А как насчёт этого: Код (Text): char str[] = "string"; ? Дело в том, что здесь константный литерал используется для инициализации неконстантного массива. Код (Text): char *str = "string"; означает вот это: Код (Text): char unnamed[] = "string"; char *str = unnamed; Но вот такой код скомпилирован не будет, если убрать const: Код (Text): char const *str = &"string"[0];
green Если я не ошибаюсь, то все-таки не означает. В unnamed хранится копия литера, а не сам литер, поэтому можно взять неконстантный указатель на неконстантную копию (более корректно - указатель на неконстантную сущность, указывающий на неконстантную копию). Массивы же умеют сводиться к указателю на первый элемент. При этом сведение (decay) не подразумевает копирования. Аналогичным образом имя free-функции сводится к указателю на функцию, естественно, без какого-либо копирования. То есть в коде char* str = "string"; не существует неконстантной копии литера, чтобы такое присваивание было возможно. А даже если бы и существовал, то это всеравно не имело бы смысла, поскольку временная копия, как и любой временный объект, была бы уничтожена после заверщающей выражение точки с запятой.
_DEN_ char *str = "string" имеет специальное значение и сводится именно к созданию анонимного массива. Скажем, в Код (Text): char *str1 = "string"; char *str2 = "string"; str1 и str2 могут иметь разные значения. Эта конструкция введена в Стандарт для большей совместимости с С, но является deprecated. Более того, такой код может привести к рантайм-ошибкам, если компилятор умеет делать string pooling.
green Думаю что массив - [], и указатель это всё таки разные вещи. asmfan Как ты компилил, что у тебя работает? У меня такой же компилятор, и падает, по листингу ничего и близко рядом с твоим нету. Может опции какие хитрые используешь? String Pooling включал/отключал, всё одно.
green Откуда такая информация? Кстати, литерная строка это действительно константа. Вот такой код: Код (Text): template <int n> void foo(char (&)[n]) { } int boo() { foo("bugaga"); } не компилица на камю с таким результатом: Код (Text): "ComeauTest.c", line 9: error: no instance of function template "foo" matches the argument list The argument types that you used are: (const char [7]) // Йо-хо-хо! foo("bugaga"); ^ "ComeauTest.c", line 10: warning: missing return statement at end of non-void function "boo" } ^ 1 error detected in the compilation of "ComeauTest.c". Значит вопрос в том, что за экзотическим поведением обладает сведение. Можешь показать место в Стандарте, где говорится об анонимном массиве?
_DEN_ Вот здесь говорится о допустимости такой конструкции: C.1.1 Clause 2 Subclause _lex.string А насчёт анонимного массива - это вопрос интерпретации. IMHO, aнонимный массив обосновывает допустимость такой конструкции. А также почему в Код (Text): char *str1 = "string"; char *str2 = "string"; str1 & str2 могут иметь разные значения. Да. И такие вот коды тоже не компилятся: Код (Text): char /*const*/ *str = &"string"[0]; "string"[0] = 0;
Код (Text): cl.exe /Fa /c /Wp64 /GS- /TC "%~nx1" вообще, логично всё, если без const - изменение возможно, если const - компилер ругается на изменение. Смущает только то, что в отдельную R-only секцию не кладётся, если const char* ptr инициализирован, но и не надо так юзать строки.
А в чем вообще проблема? Насколько, я знаю, такие вещи не являются частью стандарта. Компилятор волен поступать как хочет. В частность при использовании компилятора Microsoft, предупреждают, что строка может оказаться read-only. Не вижу смысла в этом споре.