Spec-Zone.ru › GCC 4

11.3 Несовместимости GCC

Существует несколько примечательных несовместимостей между GNU C и версиями C от К&Р (не-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 не допускает такую конструкцию.

  • Компиляторы К&Р позволяют комментариям пересекать границы включения (т. е. начинаться в файле включения и заканчиваться в включающем файле).
  • Объявления внешних переменных и функций внутри блока применяются только к блоку, содержащему объявление. Другими словами, они имеют такой же объём, как и любое другое объявление в том же месте.

    В некоторых других компиляторах 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 учитывает все символы идентификаторов как значимые. В соответствии с К&Р-1 (2.2), «Значимы только первые восемь символов, хотя можно использовать больше». Также в соответствии с К&Р-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-4.9.4/gcc/Incompatibilities.html

Spec-Zone.ru

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