Spec-Zone.ru › GCC 6

13.3 Несовместимости GCC

Существует несколько заметных несовместимостей между GNU C и K&R (не-ISO) версиями C.

  • GCC обычно делает строковые константы только для чтения. Если используются несколько строковых констант, похожих по виду, GCC хранит только одну копию строки.

    Одним из последствий является то, что вы не можете вызвать mktemp со строковой константой в качестве аргумента. Функция mktemp всегда изменяет строку, на которую указывает её аргумент.

    Ещё одним следствием является то, что sscanf не работает на некоторых очень старых системах, когда ей передаётся строковая константа в качестве строки управления форматом или входных данных. Это происходит потому, что sscanf неправильно пытается записать в строковую константу. Точно так же fscanf и scanf.

    Решение этих проблем заключается в изменении программы на использование массивов переменных char с начальными строками для этих целей вместо строковых констант.

  • -2147483648 положительно.

    Это происходит потому, что 2147483648 не помещается в тип int, поэтому (в соответствии с правилами ISO C) его тип данных — unsigned long int. Отрицание этого значения снова даёт 2147483648.

  • GCC не подставляет аргументы макросов, когда они появляются внутри строковых констант. Например, следующий макрос в GCC
    #define foo(a) "a"

    выведет "a" независимо от значения аргумента a.

  • При использовании setjmp и longjmp, единственные автоматические переменные, гарантированно сохраняющие своё значение, — это те, которые объявлены volatile. Это следствие автоматического распределения регистров. Рассмотрим эту функцию:
    jmp_buf j;
    
    foo ()
    {
      int a, b;
    
      a = fun1 ();
      if (setjmp (j))
        return a;
    
      a = fun2 ();
      /* longjmp (j) may occur in fun3. */
      return a + fun3 ();
    }

    Здесь a может или не может быть восстановлено до своего первоначального значения, когда происходит longjmp. Если a выделяется в регистре, то её первоначальное значение восстанавливается; в противном случае она сохраняет последнее сохранённое значение.

    Если вы используете опцию -W вместе с опцией -O, GCC выдаст предупреждение, если посчитает, что такая проблема может возникнуть.

  • Программы, использующие директивы препроцессора в середине аргументов макросов, не работают с GCC. Например, такая программа не будет работать:
    foobar (
    #define luser
            hack)

    ISO C не допускает такой конструкции.

  • Компиляторы K&R позволяют комментариям переходить через границу включения (т.е. начинаться в файле включения и заканчиваться в включающем файле).
  • Объявления внешних переменных и функций внутри блока применяются только к блоку, содержащему объявление. Другими словами, они имеют такой же область действия, как и любое другое объявление в том же месте.

    В некоторых других компиляторах C объявление extern влияет на весь остальной файл, даже если оно происходит внутри блока.

  • В традиционном C можно объединить long, и т.д., с именем typedef, как показано здесь:
    typedef int foo;
    typedef long foo bar;

    В ISO C это запрещено: long и другие модификаторы типов требуют явного int.

  • PCC позволяет использовать имена typedef в качестве параметров функций.
  • Традиционный C допускает появление следующей ошибочной пары объявлений вместе в данном области видимости:
    typedef int foo;
    typedef foo foo;
  • GCC обрабатывает все символы идентификаторов как значимые. Согласно K&R-1 (2.2), «Не более восьми первых символов являются значимыми, хотя больше может использоваться». Также согласно K&R-1 (2.2), «Идентификатор — это последовательность букв и цифр; первый символ должен быть буквой. Подчеркивание _ считается буквой», но GCC также допускает знаки доллара в идентификаторах.
  • PCC допускает пробелы в середине составных операторов присваивания, таких как ‘+=’. GCC, следуя стандарту ISO, этого не позволяет.
  • GCC жалуется на незавершенные символьные константы внутри условных выражений препроцессора, которые не выполняются. Некоторые программы содержат английские комментарии, заключенные в условные выражения, которые гарантированно не выполняются; если эти комментарии содержат апострофы, GCC, вероятно, сообщит об ошибке. Например, этот код вызовет ошибку:
    #if 0
    You can't expect this to work.
    #endif

    Лучшее решение такой проблемы — поместить текст в реальный C-комментарий, ограниченный ‘/*…*/’.

  • Многие пользовательские программы содержат объявление ‘long time ();’. В прошлом системные заголовочные файлы на многих системах не объявляли фактически time, поэтому тип, который ваша программа объявила для возвращаемого значения, не имел значения. Но на системах с заголовочными файлами ISO C, time объявлен для возврата time_t, и если это не то же самое, что long, то ‘long time ();’ является ошибочным.

    Решение состоит в изменении вашей программы на использование соответствующих системных заголовков (<time.h> на системах с заголовочными файлами ISO C) и не объявление time если системные заголовочные файлы его объявляют, или, если это не удается, использования time_t в качестве типа возвращаемого значения для time.

  • При компиляции функций, возвращающих float, PCC преобразует их в double. GCC фактически возвращает float. Если вы обеспокоены совместимостью с PCC, вы должны объявить свои функции для возврата double; вы можете сказать, что имеете в виду.
  • При компиляции функций, возвращающих структуры или объединения, код вывода GCC обычно использует метод, отличный от используемого в большинстве версий Unix. В результате, код, скомпилированный с GCC, не может вызывать функцию, возвращающую структуру, скомпилированную с PCC, и наоборот.

    Метод, используемый GCC, следующий: структура или объединение длиной 1, 2, 4 или 8 байтов возвращается как скаляр. Структура или объединение любого другого размера хранятся по адресу, предоставленному вызывающей стороной (обычно в специальном фиксированном регистре, но на некоторых машинах он передаётся в стеке). Целевой крючок TARGET_STRUCT_VALUE_RTX указывает GCC, куда передавать этот адрес.

    В отличие от этого, PCC на большинстве целевых машин возвращает структуры и объединения любого размера, копируя данные в область статической памяти, а затем возвращая адрес этой памяти, как если бы это было значение указателя. Вызывающая сторона должна скопировать данные из этой области памяти в место, где нужно значение. GCC не использует этот метод, потому что он медленнее и нереентерабелен.

    На некоторых более новых машинах PCC использует реентерабельный соглашение для всех структур и объединений. GCC на большинстве этих машин использует совместимое соглашение при возврате структур и объединений в памяти, но всё ещё возвращает небольшие структуры и объединения в регистрах.

    Вы можете указать GCC использовать совместимое соглашение для всех возвращаемых структур и объединений с опцией -fpcc-struct-return.

  • GCC жалуется на фрагменты программы, такие как ‘0x74ae-0x4000’, которые, похоже, представляют собой две шестнадцатеричные константы, разделенные оператором минус. На самом деле, эта строка является одним маркером препроцессора. Каждый такой маркер должен соответствовать одному маркеру в C. Поскольку это не так, GCC выводит сообщение об ошибке.
  • Хотя может показаться очевидным, что подразумевается оператор и два значения, стандарт ISO C чётко требует, чтобы это рассматривалось как ошибочный случай.

    Маркер препроцессора является числом препроцессора, если он начинается с цифры и за ней следуют буквы, нижние подчеркивания, цифры, точки и последовательности символов ‘e+’, ‘e-’, ‘E+’, ‘E-’, ‘p+’, ‘p-’, ‘P+’ или ‘P-’. (В строгом режиме C90 последовательности ‘p+’, ‘p-’, ‘P+’ и ‘P-’ не могут появляться в числах препроцессора.)

    Чтобы сделать фрагмент программы выше корректным, поместите пробел перед знаком минус. Этот пробел завершит число препроцессора.

Далее: Фиксированные заголовки, Предыдущее: Взаимодействие, Выше: Проблемы [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-6.5.0/gcc/Incompatibilities.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API