× К оглавлению На главную Об авторе

Дата и время публикации:    
Дата и время модификации:

## 1. Назначение ### 1.1 Редакцию стандарта ISO С В компиляторе gcc версия стандарта ISO С определяется макросами ```__STDC__``` и ```__STDC_VERSION__``` : Макрос ```__STDC__``` [расширяется](https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html) до единичной константы, чтобы показать, что данный компилятор соответствует стандарту ```ISO C``` (_ISO Standard C_). Макрос ```__STDC_VERSION__``` расширяется до числовой версии стандарта С, являясь константным значением длинного целого в форме ```yyyymmL```, где ```yyyy``` и ```mm``` содержат значения года и месяца выхода стандарта. Мaкрос ```__STRICT_ANSI__``` появиться, если были применены строгие требования к соблюдению стандарта через опцию -std или -ansi . Так, значение макроса означает [использование](https://github.com/cpredef/predef/blob/master/Standards.md) редакции стандарта С и задается [опцией -std](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) : | Name| Macro | Standard | Option | |------|---------------------------------|---------------------|--------------------| | C89 | ```__STDC__``` | ANSI X3.159-1989 | -std=c89, -ansi | | C90 | ```__STDC__``` | ISO/IEC 9899:1990 | -std=c90, iso9899:1990 | | C94 | ```__STDC_VERSION__ = 199409L```| ISO/IEC 9899-1:1994 | iso9899:199409 | | C99 | ```__STDC_VERSION__ = 199901L```| ISO/IEC 9899:1999 | c99, iso9899:1999| | C11 | ```__STDC_VERSION__ = 201112L```| ISO/IEC 9899:2011 | c1x, iso9899:2024| | C17 | ```__STDC_VERSION__ = 201710L```| ISO/IEC 9899:2018 | c17, -pedantic | | C23 | ```__STDC_VERSION__ = 202311L```| ISO/IEC 9899:2024 | c23 | Значения опции компилятора -std, поддерживающие GNU диалект и соответствующие стандарту : * ```gnu90, gnu89``` ─ стандарту ```ISO C90```, * ```gnu99, gnu9x``` ─ стандарту ```ISO C99```, * ```gnu11, gnu1x``` ─ стандарту ```ISO C11```, * ```gnu17, gnu18``` ─ стандарту ```ISO C17```, * ```gnu23, gnu2x``` ─ стандарту ```ISO C23``` . Соответственно, если будет задана одно из только что выше перечисленых значений опции -std, ```__STRICT_ANSI__``` не будет определена. Начиная с версии ```GCC 14.2```, [использовать](https://gcc.gnu.org/releases.html) ```gnu2x``` запрещено. Для того, чтобы быстро [определить](https://stackoverflow.com/a/68717818/24648605) какие редакции стандарта С поддерживает компилятор, нужно в командной строке задать:

    $ gcc --version && gcc -dM -E - < /dev/null| grep "__STDC_"

    gcc (Debian 10.2.1-6) 10.2.1 20210110
    Copyright (C) 2020 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    #define __STDC_HOSTED__ 1
    #define __STDC_UTF_16__ 1
    #define __STDC_IEC_559__ 1
    #define __STDC_ISO_10646__ 201706L
    #define __STDC_IEC_559_COMPLEX__ 1
    #define __STDC_VERSION__ 201710L
    #define __STDC_UTF_32__ 1
    #define __STDC__ 1

Как следует из вывода, компилятор gcc поддерживает C89, так же называемый ANSI C, или ISO C90, потому что макрос ```__STDC__``` расширен до 1 . В тоже время, макросу __STDC_VERSION__ установлено значение ```201710L```, что соответствует стандарту ```ISO/IEC 9899:2018``` . При этом следует помнить, что когда ```-std=c89```, ```-ansi``` и ```iso9899:1990``` макрос ```__STDC_VERSION__``` не будет определен, но появиться макрос ```__STRICT_ANSI__``` :

    $ gcc --version && gcc -std=c89 -dM -E - < /dev/null| grep "__STDC_\|STRICT_ANSI"

    gcc (Debian 10.2.1-6) 10.2.1 20210110
    Copyright (C) 2020 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    #define __STDC_HOSTED__ 1
    #define __STDC_IEC_559__ 1
    #define __STDC_ISO_10646__ 201706L
    #define __STDC_IEC_559_COMPLEX__ 1
    #define __STRICT_ANSI__ 1
    #define __STDC__ 1

### 1.2 Откланение от редакции стандарта ```ISO С``` В компиляторе GCC реализованы [свои собственные расширения](https://rjaan.narod.ru/docs/dev/gnucs/gcc-extensions.html), которые отсутствуют в стандарте ISO языка С. Так, если указать опцию -pedantic или -Wpedantic, на выходе GCC закидает предупреждающими сообщениями, если встретит что-то в обход стандарта. Поэтому, когда используются такого рода опции или -std с перечисленными выше значениями, нужно учитывать, что какое-либо отклонение от стандарта может сопровождаться не только выдачей ни к чему обязывающих сообщений, но и заставят компилятор завершить работу с ошибкой. Поэтому рекомендуется использовать опцию ```-pedantic```, чтобы находить в коде отклонения от стандартов ```ISO C``` в виде расширений GCC через формирование предупреждений о их наличии. А использование вместе опции ```-std=c89 -pedantic``` [позволят](https://stackoverflow.com/a/2855148/24648605) легко портировать код между различными компиляторами на их платформах. ## 2. Использование ### 2.1 Определение редакции стандарта ISO C Из всех вариантов определения и предопределения редакции ISO C мне приглянулся проект [cpredef/predef](https://github.com/cpredef/predef/blob/master/Standards.md), который предлагает предопределять по макросам ```__STDC__``` и ```__STDC_VERSION__``` макрос ```PREDEF_STANDARD_C_yyyy``` через макро if-выражение, определяя ```yyyy``` согласно значения в макрос ```__STDC_VERSION__``` с некоторыми правками для компилятора GCC :

    ...
   /* abi_common.h */
    ...
    #if defined(__STDC__) && defined(__STRICT_ANSI__)
    # define PREDEF_STANDARD_C_ANSI     0x0c89
    # if defined(__STDC_VERSION__)
    #  if (__STDC_VERSION__ >= 199409L)
    #   define PREDEF_STANDARD_C_1994   0x0c94
    #  endif
    #  if (__STDC_VERSION__ >= 199901L) 0x0c99
    #   define PREDEF_STANDARD_C_1999
    #  endif
    #  if (__STDC_VERSION__ >= 201112L)
    #    define PREDEF_STANDARD_C_2011  0x0c99
    #  endif
    #  if (__STDC_VERSION__ >= 201710L) 0x0c18
    #   define PREDEF_STANDARD_C_2018
    #  endif
    #  if (__STDC_VERSION__ >= 202311L)
    #    define PREDEF_STANDARD_C_2023 0x0c23
    #  endif
    # endif
    # elif defined(__STDC__) && !defined(__STRICT_ANSI__)
    #  define PREDEF_STANDARD_GNUC  0xfc00 
    #endif
    ...

Макрос PREDEF_STANDARD_GNUC будет определен, если ```__STRICT_ANSI__``` не будет в свою очередь установлен черз опцию ```-std``` или ```-ansi``` . Соответственно, чтобы избежать ошибок, когда компилятору будет указана опция ```-std=c89``` или ```-ansi``` проект [cpredef/predef](https://github.com/cpredef/predef/blob/master/Standards.md) рекомендует использовать макрос PREDEF_STANDARD_C_yyyy, например для "удаления" ключевых слов, таких как :

    #if ( PREDEF_STANDARD_C == PREDEF_STANDARD_C_ANSI)
    # define const
    # define volatile
    #endif

В некоторых случаях, например, inline-функций :

    ...
    #if (PREDEF_STANDARD_C >= PREDEF_STANDARD_C_1999)
        inline int foo(int a, int b) {  return ( 2 * (b+a) ) ; }                                                                                                                                                   
    #else       
    #   define foo(a,b) (2 * (b+a))  
    #endif /* PREDEF_STANDARD_C_1999 */
    ...
    int a = 5,
        b = 3,
        c;
    c = foo(a,b);  /* c=16 */

Необходимо проверять, что предустановленный стандарт компилятору будет отвечать как минимуму ISO/IEC 9899:1999 , в котором появилась поддержка inline-функций. В противном случае, следует использовать макроопределение, содержащее арифметическое выражение ```2 * (b+a)``` . ### 2.2 Определение отклонений от стандарта GNU C Наличие опции ```-pedantic``` позволяет найти отклонения от стандарта GNU C, например, использование расширений компилятора GCC :

    vim float_to_binconv.c
    ...
    19 #define MSB_FIND(n)({\
    20      unsigned int __n = (unsigned int)n,\
    21      __idx = 0, __ctx = -1; \
    ...
    28      1 << __idx ;})
    ...

Попытка компиляции файла ```float_to_binconv.c``` с опцией ```-pedantic``` приведет к выводу сообщения ```-Wpedantic```, что запрещено использовать операторы-выражения в ISO C :

    gcc -pedantic float_to_binconv.c -o float_to_binconv 
    float_to_binconv.c: In function ‘main’:
    float_to_binconv.c:19:20: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
    19 | #define MSB_FIND(n)({\
       |                    ^
    ...

 

Яндекс.Метрика