Spec-Zone.ru › GCC 14

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

Spec-Zone.ru

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