Spec-Zone.ru › GCC 8

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

Spec-Zone.ru

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