Spec-Zone.ru › GCC 5

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

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

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

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

Spec-Zone.ru

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