Spec-Zone.ru › GCC 7

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

Spec-Zone.ru

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