Spec-Zone.ru › GCC 12

14.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-12.2.0/gcc/Incompatibilities.html

Spec-Zone.ru

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