Comeau и указатель на литерную строку

Тема в разделе "LANGS.C", создана пользователем _DEN_, 17 фев 2009.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Я что-то упустил? С каких пор на литерную строку можно брать неконстантный указатель?

    Код (Text):
    1. char* str = "string";
    http://www.comeaucomputing.com/tryitout/
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_
    Что-то странное с этим.
    VS 2003 такое компилит:
    Код (Text):
    1. #include <iostream>
    2. void foo()
    3. {
    4.     char* str = "string_abcdef";
    5.     std::cout<<str<<std::endl;
    6. }
    7.  
    8. int main(int argc, char* argv[])
    9. {
    10.     char* str = "string_abcdef";
    11.     str[0] = '1';
    12.     foo();
    13. }
    Но на строке str[0] = '1'; получаем access violation.
    Посмотрел в ольке. Оказалось что оба указателя указывают на адрес в секции rdata, которая с правами read. ^) VS 2005 тоже валиться. ^)

    P.S Вобщем присвоили константную строку указателю на не константу, и сидим довольные.
    А компилятору на это до лампочки.
     
  3. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Booster

    Майкрософтовские компиляторы, как впрочем и все остальные, никогда не были показателями качества с точки зрения стандарта. Проверка чего-либо на VS 200X - это как анекдот про Мойше и Beatles. Только Comeau имеет репутацию компилятора, практически на 100% следующего Стандарту.

    Если я все правильно помню, то еще совсем недавно Comeau эту конструкцию не компилировал, ругаясь на то, что "Cannot convert const char[6] to char*"
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_
    Я и не против. Возможно эта конструкция для совместимости с Си.
     
  5. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Booster

    Comeau это не тот компилятор, который пойдет на отступление от Стандарта, ради какой-то там совместимости :derisive: Кроме того, такая совместимость, по мимо нарушения Стандарта, просто не имеет смысла, по скольку у каждого уважающего себя компилятора есть два отдельных режима: Compite as C и Compile as C++. Как вариант, ни студия, ни камю не будут компилировать по правилам C++ например вот такую конструкцию

    Код (Text):
    1. void foo(int const n)
    2. {
    3.     char array[n];
    4. }
    несмотря на то, что это законный C99
     
  6. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
    Код (Text):
    1. char* foo()
    2. {
    3.     char* str = "string_abcdef";
    4.     str[1] = '2';
    5.     return str;
    6. }
    7.  
    8. int main(int argc, char* argv[])
    9. {
    10.     char* str = "string_abcdef";
    11.     str[0] = '1';
    12.     return (int)foo()[1];
    13. }
    Выдаёт
    Код (Text):
    1. ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.346
    2.  
    3.         TITLE   C:\WINDOWS\Temp\CL\x32\1.c
    4.         .686P
    5.         .XMM
    6.         include listing.inc
    7.         .model  flat
    8.  
    9. INCLUDELIB LIBCMT
    10. INCLUDELIB OLDNAMES
    11.  
    12. _DATA   SEGMENT
    13. $SG607  DB      'string_abcdef', 00H
    14.         ORG $+2
    15. $SG615  DB      'string_abcdef', 00H
    16. _DATA   ENDS
    17. PUBLIC  _foo
    18. ; Function compile flags: /Odtp
    19. _TEXT   SEGMENT
    20. _str$ = -4                                              ; size = 4
    21. _foo    PROC
    22. ; File c:\windows\temp\cl\x32\1.c
    23. ; Line 2
    24.         push    ebp
    25.         mov     ebp, esp
    26.         push    ecx
    27. ; Line 3
    28.         mov     DWORD PTR _str$[ebp], OFFSET $SG607
    29. ; Line 4
    30.         mov     eax, DWORD PTR _str$[ebp]
    31.         mov     BYTE PTR [eax+1], 50                    ; 00000032H
    32. ; Line 5
    33.         mov     eax, DWORD PTR _str$[ebp]
    34. ; Line 6
    35.         mov     esp, ebp
    36.         pop     ebp
    37.         ret     0
    38. _foo    ENDP
    39. _TEXT   ENDS
    40. PUBLIC  _main
    41. ; Function compile flags: /Odtp
    42. _TEXT   SEGMENT
    43. _str$ = -4                                              ; size = 4
    44. _argc$ = 8                                              ; size = 4
    45. _argv$ = 12                                             ; size = 4
    46. _main   PROC
    47. ; Line 9
    48.         push    ebp
    49.         mov     ebp, esp
    50.         push    ecx
    51. ; Line 10
    52.         mov     DWORD PTR _str$[ebp], OFFSET $SG615
    53. ; Line 11
    54.         mov     eax, DWORD PTR _str$[ebp]
    55.         mov     BYTE PTR [eax], 49                      ; 00000031H
    56. ; Line 12
    57.         call    _foo
    58.         movsx   eax, BYTE PTR [eax+1]
    59. ; Line 13
    60.         mov     esp, ebp
    61.         pop     ebp
    62.         ret     0
    63. _main   ENDP
    64. _TEXT   ENDS
    65. END
    Т.е. кладёт в RW секцию данных.

    Microsoft (R) C/C++ Optimizing Compiler Version 14.00.50727.762 for x64
    выдаёт:
    Код (Text):
    1. ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.346
    2.  
    3. include listing.inc
    4.  
    5. INCLUDELIB LIBCMT
    6. INCLUDELIB OLDNAMES
    7.  
    8. _DATA   SEGMENT
    9. $SG536  DB      'string_abcdef', 00H
    10.         ORG $+2
    11. $SG544  DB      'string_abcdef', 00H
    12. _DATA   ENDS
    13. PUBLIC  foo
    14. pdata   SEGMENT
    15. $pdata$foo DD   imagerel $LN3
    16.         DD      imagerel $LN3+32
    17.         DD      imagerel $unwind$foo
    18. pdata   ENDS
    19. xdata   SEGMENT
    20. $unwind$foo DD  010401H
    21.         DD      02204H
    22. ; Function compile flags: /Odtp
    23. xdata   ENDS
    24. _TEXT   SEGMENT
    25. str$ = 0
    26. foo     PROC
    27. ; File c:\windows\temp\cl\x64\1_64.c
    28. ; Line 2
    29. $LN3:
    30.         sub     rsp, 24
    31. ; Line 3
    32.         lea     rax, OFFSET FLAT:$SG536
    33.         mov     QWORD PTR str$[rsp], rax
    34. ; Line 4
    35.         mov     rax, QWORD PTR str$[rsp]
    36.         mov     BYTE PTR [rax+1], 50                    ; 00000032H
    37. ; Line 5
    38.         mov     rax, QWORD PTR str$[rsp]
    39. ; Line 6
    40.         add     rsp, 24
    41.         ret     0
    42. foo     ENDP
    43. _TEXT   ENDS
    44. PUBLIC  main
    45. pdata   SEGMENT
    46. $pdata$main DD  imagerel $LN3
    47.         DD      imagerel $LN3+47
    48.         DD      imagerel $unwind$main
    49. pdata   ENDS
    50. xdata   SEGMENT
    51. $unwind$main DD 010d01H
    52.         DD      0620dH
    53. ; Function compile flags: /Odtp
    54. xdata   ENDS
    55. _TEXT   SEGMENT
    56. str$ = 32
    57. argc$ = 64
    58. argv$ = 72
    59. main    PROC
    60. ; Line 9
    61. $LN3:
    62.         mov     QWORD PTR [rsp+16], rdx
    63.         mov     DWORD PTR [rsp+8], ecx
    64.         sub     rsp, 56                                 ; 00000038H
    65. ; Line 10
    66.         lea     rax, OFFSET FLAT:$SG544
    67.         mov     QWORD PTR str$[rsp], rax
    68. ; Line 11
    69.         mov     rax, QWORD PTR str$[rsp]
    70.         mov     BYTE PTR [rax], 49                      ; 00000031H
    71. ; Line 12
    72.         call    foo
    73.         movsx   eax, BYTE PTR [rax+1]
    74. ; Line 13
    75.         add     rsp, 56                                 ; 00000038H
    76.         ret     0
    77. main    ENDP
    78. _TEXT   ENDS
    79. END
    Что тоже в RW.

    Пример бажный заведомо, т.к. некоторые компилеры кладут локальные строки на стэк, но это не суть.
    Можно проследитЬ, что указатель хранится как указатель, т.е. в памяти при некоторых компилерах и при явном указании static в случае CL.
    Обе программы исполняются верно, не вызывая исключений.
    Так и не удалось заставить CL засунуть саму строку в секцию R-only при использовании указателей. Зато работает как надо для строк вида const str[]=... причём при таком раскладе как правило никода сам указатель нигде не хранится, а используется непосредственно адрес строки.
     
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    asmfan

    Это все безумно интересно, но меня волнует несколько другое :) Почему Comeau это компилирует? У меня помутнение памяти и это компилилось всегда? Или же что-то случилось с Comeau? Или поменяли Стандарт? На сколько я помню, все литерные значения всегда трактовались как const.
     
  8. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _DEN_
    Я имел ввиду то, что вполне возможно это есть стандарт С++, в целях совместимости с Си. Ведь в С++ много такого барахла.
    У комею тоже всякие деприкейтед опции есть.
     
  9. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    А как насчёт этого:
    Код (Text):
    1. char str[] = "string";
    ?
    Дело в том, что здесь константный литерал используется для инициализации неконстантного массива.
    Код (Text):
    1. char *str = "string";
    означает вот это:
    Код (Text):
    1. char unnamed[] = "string";
    2. char *str = unnamed;
    Но вот такой код скомпилирован не будет, если убрать const:
    Код (Text):
    1. char const *str = &"string"[0];
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Если я не ошибаюсь, то все-таки не означает. В unnamed хранится копия литера, а не сам литер, поэтому можно взять неконстантный указатель на неконстантную копию (более корректно - указатель на неконстантную сущность, указывающий на неконстантную копию). Массивы же умеют сводиться к указателю на первый элемент. При этом сведение (decay) не подразумевает копирования. Аналогичным образом имя free-функции сводится к указателю на функцию, естественно, без какого-либо копирования. То есть в коде char* str = "string"; не существует неконстантной копии литера, чтобы такое присваивание было возможно. А даже если бы и существовал, то это всеравно не имело бы смысла, поскольку временная копия, как и любой временный объект, была бы уничтожена после заверщающей выражение точки с запятой.
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    char *str = "string" имеет специальное значение и сводится именно к созданию анонимного массива.
    Скажем, в
    Код (Text):
    1. char *str1 = "string";
    2. char *str2 = "string";
    str1 и str2 могут иметь разные значения.

    Эта конструкция введена в Стандарт для большей совместимости с С, но является deprecated.
    Более того, такой код может привести к рантайм-ошибкам, если компилятор умеет делать string pooling.
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    green
    Думаю что массив - [], и указатель это всё таки разные вещи.

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

    String Pooling включал/отключал, всё одно.
     
  13. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Откуда такая информация?


    Кстати, литерная строка это действительно константа. Вот такой код:

    Код (Text):
    1. template <int n>
    2. void foo(char (&)[n])
    3. {
    4.  
    5. }
    6.  
    7. int boo()
    8. {
    9.     foo("bugaga");
    10. }
    не компилица на камю с таким результатом:

    Код (Text):
    1. "ComeauTest.c", line 9: error: no instance of function template "foo" matches the
    2.           argument list
    3.             The argument types that you used are: (const char [7]) // Йо-хо-хо!
    4.       foo("bugaga");
    5.       ^
    6.  
    7. "ComeauTest.c", line 10: warning: missing return statement at end of non-void
    8.           function "boo"
    9.   }
    10.   ^
    11.  
    12. 1 error detected in the compilation of "ComeauTest.c".
    Значит вопрос в том, что за экзотическим поведением обладает сведение. Можешь показать место в Стандарте, где говорится об анонимном массиве?
     
  14. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Вот здесь говорится о допустимости такой конструкции:
    C.1.1 Clause 2 Subclause _lex.string

    А насчёт анонимного массива - это вопрос интерпретации. IMHO, aнонимный массив обосновывает допустимость такой конструкции.
    А также почему в
    Код (Text):
    1. char *str1 = "string";
    2. char *str2 = "string";
    str1 & str2 могут иметь разные значения.
    Да. И такие вот коды тоже не компилятся:
    Код (Text):
    1. char /*const*/ *str = &"string"[0];
    2. "string"[0] = 0;
     
  15. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Код (Text):
    1. cl.exe /Fa /c /Wp64 /GS- /TC "%~nx1"
    вообще, логично всё, если без const - изменение возможно, если const - компилер ругается на изменение. Смущает только то, что в отдельную R-only секцию не кладётся, если const char* ptr инициализирован, но и не надо так юзать строки.
     
  16. Forever

    Forever Виталий

    Публикаций:
    0
    Регистрация:
    12 апр 2008
    Сообщения:
    244
    А в чем вообще проблема? Насколько, я знаю, такие вещи не являются частью стандарта. Компилятор волен поступать как хочет. В частность при использовании компилятора Microsoft, предупреждают, что строка может оказаться read-only. Не вижу смысла в этом споре.
     
  17. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    из стандарта:
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    asmfan
    Код (Text):
    1. cl.exe /Fa /c /Wp64 /GS- /TC /ZI "%~nx1"
     
  19. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Booster да, за код отвечают c1, c2, c1xx дллы, а не сам cl.
     
  20. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    asmfan
    Не понял, это к чему?