Spec-Zone.ru › GCC 10

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

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

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

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

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

Spec-Zone.ru

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