Spec-Zone.ru › GCC 11

Следующая: Исправленные заголовочные файлы, Предыдущая: Взаимодействие, Вверх: Известные причины проблем с GCC [Оглавление][Индекс]

14.3 Несовместимости GCC ¶

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

  • 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-’ не могут появляться в препроцессорных числах.)

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

Следующая: Исправленные заголовочные файлы, Предыдущая: Взаимодействие, Вверх: Известные причины проблем с GCC [Оглавление][Индекс]

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

Spec-Zone.ru

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