第9章:コンパイラ拡張と標準適合

この章で学ぶこと

  • GCC/Clangの主要な拡張
  • __attribute__ の活用
  • コンパイラオプションと標準モード
  • 拡張を使わない移植可能なコード
  • ---

    9.1 コンパイラ拡張とは

    定義

    標準規格で規定されていない機能。コンパイラ固有。

    よく使われる拡張

  • __attribute__
  • typeof(C23で標準化)
  • Statement expressions
  • Nested functions(GCCのみ)
  • ---

    9.2 GCC/Clang の __attribute__

    関数属性

    /* 非戻り関数 */
    void die(const char *msg) __attribute__((noreturn));
    
    /* 純粋関数(副作用なし、同じ引数で同じ結果) */
    int square(int x) __attribute__((pure));
    
    /* 定数関数(グローバル状態も参照しない) */
    int add(int a, int b) __attribute__((const));
    
    /* printf形式のチェック */
    void log_msg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
    
    /* 非推奨 */
    void old_api(void) __attribute__((deprecated("use new_api instead")));
    
    /* インライン化を強制 */
    __attribute__((always_inline)) inline int fast_op(int x);
    

    変数属性

    /* アラインメント */
    int data __attribute__((aligned(16)));
    
    /* セクション指定 */
    int persistent __attribute__((section(".data")));
    
    /* 未使用警告を抑制 */
    int reserved __attribute__((unused));
    

    型属性

    /* パックド構造体(パディングなし) */
    struct __attribute__((packed)) packet {
        uint8_t type;
        uint32_t data;
    };
    

    ---

    9.3 C23での標準化

    属性構文

    /* C23標準属性 */
    [[noreturn]] void die(const char *msg);
    [[deprecated("use new_api")]] void old_api(void);
    [[maybe_unused]] int reserved;
    [[nodiscard]] int important_func(void);
    

    typeof

    /* C23で標準化 */
    int x = 42;
    typeof(x) y = x;  /* int y = x; と同等 */
    typeof_unqual(const int) z;  /* int z; */
    

    ---

    9.4 標準モードの指定

    GCC/Clang オプション

    # 標準モード
    gcc -std=c89 file.c
    gcc -std=c99 file.c
    gcc -std=c11 file.c
    gcc -std=c17 file.c
    gcc -std=c23 file.c
    
    # GNU拡張付き(デフォルト)
    gcc -std=gnu11 file.c
    
    # 厳格な標準適合
    gcc -std=c11 -pedantic file.c
    gcc -std=c11 -pedantic-errors file.c
    

    拡張の検出

    #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
        /* GCC拡張が利用可能 */
    #endif
    
    #if __STDC_VERSION__ >= 201112L
        /* C11以降 */
    #endif
    
    #if __STDC_VERSION__ >= 202311L
        /* C23以降 */
    #endif
    

    ---

    9.5 移植可能なコード

    属性のラッパー

    #if defined(__GNUC__) || defined(__clang__)
        #define NORETURN __attribute__((noreturn))
        #define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
    #elif defined(_MSC_VER)
        #define NORETURN __declspec(noreturn)
        #define PRINTF_LIKE(f, a)
    #else
        #define NORETURN
        #define PRINTF_LIKE(f, a)
    #endif
    

    C23対応

    #if __STDC_VERSION__ >= 202311L
        #define NODISCARD [[nodiscard]]
    #elif defined(__GNUC__)
        #define NODISCARD __attribute__((warn_unused_result))
    #else
        #define NODISCARD
    #endif
    

    ---

    9.6 Statement Expressions(GCC拡張)

    /* 複合文を式として使用 */
    #define max(a, b) ({        \
        typeof(a) _a = (a);     \
        typeof(b) _b = (b);     \
        _a > _b ? _a : _b;      \
    })
    
    int m = max(x++, y++);  /* x++, y++ は一度だけ評価 */
    

    注意: GCC/Clang固有。移植性なし。

    ---

    9.7 この章のまとめ

    GCC/Clang拡張

  • __attribute__((noreturn)), __attribute__((format))
  • typeof(C23で標準化)
  • Statement expressions
  • 標準適合

  • -std=cXX -pedantic で厳格モード
  • 拡張を使う場合はラッパーマクロで

---

確認問題

問題1

-pedantic オプションの効果は?

解答

標準規格で規定されていない拡張を使用した場合に警告を発する。-pedantic-errors ではエラーになる。

問題2

__attribute__((pure))__attribute__((const)) の違いは?

解答

  • pure: 副作用なし、同じ引数で同じ結果を返す(グローバル変数の読み取りは許可)
  • const: より厳しい。グローバル状態も参照しない。

---

次の章では、C23と将来の展望について学びます。