言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

C言語辞典

  1. トップページ
  2. C言語辞典
  3. #pragma / #error / #warning

#pragma / #error / #warning

対応: #pragma / #error C89(1989)
#warning C23(2023)

プリプロセッサの補助的な命令です。『#pragma』はコンパイラ固有の動作を制御し、『#error』はコンパイルを強制中断してメッセージを表示します。『#warning』は警告メッセージを出力します。

構文

// コンパイラ固有の制御を行います(コンパイラによって動作が異なります)。
#pragma 命令

// 二重インクルード防止の簡潔な記法です(多くのコンパイラがサポート)。
#pragma once

// コンパイルを強制停止してエラーメッセージを表示します。
#error エラーメッセージ

// 警告メッセージを表示します(GCC / Clang などでサポート)。
#warning 警告メッセージ

// 構造体のパディングを制御します(移植性に注意)。
#pragma pack(n) // n バイト境界でアライメントします。
#pragma pack() // デフォルト設定に戻します。

主な命令一覧

命令概要
#pragma onceそのヘッダファイルを1度だけインクルードすることをコンパイラに指示します。多くのコンパイラで対応していますが、C標準ではありません。
#pragma pack(n)構造体のメンバアライメントをnバイト境界に設定します。ネットワークプロトコルや外部バイナリ形式と構造体を合わせる際に使います。
#pragma warning特定の警告を有効化・無効化します(Visual C++ などでサポート)。
#errorプリプロセッサ段階でコンパイルを中断し、指定したメッセージをエラーとして表示します。
#warningプリプロセッサ段階で警告メッセージを表示します。コンパイルは継続されます。GCC・Clangでサポートされています。

サンプルコード

myheader.h

myheader.h の例です。

#pragma once

#define MY_HEADER_DEFINED

/* C99 以降が必要な場合の強制チェック */
#if __STDC_VERSION__ < 199901L
    #error "このコードはC99以降が必要です。"
#endif
pragma_pack_example.c

pragma_pack_example.c の例です。

#include <stdio.h>

/* ネットワークパケット構造体(パディングなし)。 */
#pragma pack(1)
typedef struct {
    unsigned char type;
    unsigned short length;
    unsigned int data;
} PacketHeader;
#pragma pack()

/* パディングありの場合と比較します。 */
typedef struct {
    unsigned char type;
    unsigned short length;
    unsigned int data;
} PacketHeaderPadded;

int main(void) {
    printf("pack(1) のサイズ: %zu バイト\n", sizeof(PacketHeader));
    printf("通常のサイズ: %zu バイト\n", sizeof(PacketHeaderPadded));
    return 0;
}

コンパイルして実行すると次のようになります。

gcc pragma_pack_example.c -o pragma_pack_example
./pragma_pack_example
pack(1) のサイズ: 7 バイト
通常のサイズ: 8 バイト

#warning で非推奨コードに警告を出す

#warning は GCC・Clang でサポートされている非標準命令です。API の廃止予告などを知らせるのに使います。コンパイルは継続されます。

pragma_warning_example.c
#include <stdio.h>

/* 将来削除予定の関数に警告を出します。 */
#warning "old_func() は非推奨です。new_func() を使ってください。"

void old_func(void) {
    printf("old_func\n");
}

void new_func(void) {
    printf("new_func\n");
}

int main(void) {
    new_func();
    return 0;
}

コンパイルして実行すると次のようになります。

gcc pragma_warning_example.c -o pragma_warning_example
pragma_warning_example.c: warning: old_func() は非推奨です。new_func() を使ってください。
./pragma_warning_example
new_func

よくあるミス

よくあるミス: #pragma pack を解除しない

#pragma pack(1) を設定したあとに pack() でリセットしないと、以降の構造体すべてにパディングなしが適用されてしまいます。

#include <stdio.h>

/* NG: pack(1) を解除しないと以降の構造体も影響を受ける */
#pragma pack(1)
typedef struct { unsigned char a; int b; } Packed;

/* こちらも pack(1) が適用されてしまう */
typedef struct { char x; double y; } AlsoAffected;

int main(void) {
    printf("Packed: %zu\n", sizeof(Packed)); /* 5 バイト */
    printf("AlsoAffected: %zu\n", sizeof(AlsoAffected)); /* 9 バイト(本来は16)*/
    return 0;
}
pragma_pack_ok.c
#include <stdio.h>

#pragma pack(1)
typedef struct { unsigned char a; int b; } Packed;
#pragma pack() /* OK: 必ず解除する */

typedef struct { char x; double y; } Normal;

int main(void) {
    printf("Packed: %zu\n", sizeof(Packed)); /* 5 バイト */
    printf("Normal: %zu\n", sizeof(Normal)); /* 通常のアライメント(16 バイト等) */
    return 0;
}

修正後は次の通りです。

gcc pragma_pack_ok.c -o pragma_pack_ok
./pragma_pack_ok
Packed: 5
Normal: 16

概要

『#pragma』は規格上「コンパイラが認識しない場合は無視する」と定められています。そのためコンパイラごとにサポートされる命令が異なります。『#pragma pack』は構造体のメモリ配置を変更するため、誤用するとアライメント違反を引き起こしてパフォーマンス低下やクラッシュを招くことがあります。ネットワークパケットなど特定の目的に限って使用してください。

『#error』は必須の前提条件(C規格バージョン・特定のマクロ定義・ターゲットアーキテクチャなど)を強制チェックするのに役立ちます。条件付きコンパイルと組み合わせることで、誤った環境でのビルドを早期に検出できます。

条件付きコンパイルの詳細は『#ifdef / #ifndef / #endif』を、マクロ定義については『#include / #define(定数)』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。