Spec-Zone.ru › GCC 9

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

Spec-Zone.ru

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