【C言語】
#ifdefと#ifの違いは
定義済みか非ゼロかの扱い

■この記事の概要

この記事では、C言語のプリプロセッサディレクティブ#ifdef#ifの違いを解説しています。#ifdefはマクロが定義済みかどうかを確認し、#ifは評価式が非ゼロかどうかを確認します。コード例を交えて推奨される使い方やエラー防止策も詳述されています。


■#ifdefは定義済みなら成立

#include <stdio.h>
int main(void){
//DEBUG未定義
#ifdef      DEBUG
            puts("来ない");
#endif

//gcc -DDEBUG=0相当
#define     DEBUG   0 
#ifdef      DEBUG   //定義済み  
    printf("%d:来る\n",__LINE__);
#endif

//gcc -DDEBUG 相当
#undef      DEBUG   //定義取り消し
#define     DEBUG   1 
#ifdef      DEBUG   //定義済み
    printf("%d:来る\n",__LINE__);
#endif
}

#ifdef DEBUG
DEBUGマクロが
定義済みなら成立し
未定義なら成立しません。

DEBUGの値がゼロか非ゼロかは
関係ありません。


■#ifは非ゼロなら成立

#include <stdio.h>
int main(void){
//DEBUG未定義    
#if     DEBUG
    puts("来ない");
#endif
//gcc -DDEBUG=0相当
#define     DEBUG   0 
#if         DEBUG   //ゼロ
    puts("来ない");
#endif
//gcc -DDEBUG 相当
#undef      DEBUG   //定義取り消し
#define     DEBUG   1 
#if         DEBUG   //非ゼロ
    printf("%d:来る\n",__LINE__);
#endif
//gcc -DDEBUG=2相当
#undef      DEBUG   //定義取り消し
#define     DEBUG   2   
#if         DEBUG <= 1  //偽=ゼロ
    puts("来ない");
#endif
#if         DEBUG <= 2  //真=非ゼロ
    printf("%d:来る\n",__LINE__);
#endif
}

#if DEBUG
DEBUG式が
非ゼロなら成立し
ゼロなら成立しません。

DEBUGの所に
if DEBUG <= 2 のような
式を書く事ができます。
デバッグレベルに応じて
展開を制御する時によく使います。


■#ifと#endifしか使っていない例(非推奨)

char    *cpu[]={
    "z80",
#if     CPU==3
    "Core i3"
#endif
#if   CPU==5
    "Core i5"
#endif
#if   CPU==7
    "Core i7"
#endif
#if   CPU==9
    "Core i9"
#endif
};
#include <stdio.h>
int main(void){
    printf("%s\n",cpu[1]);//cpu[1]が展開されない場合暴走するかも
}

gcc -DCPU=9等とコンパイル時に適切な引数が与えられた時は問題がありませんが
gcc -DCPU=1234等と指定された場合コンパイルエラーにならず、
プログラム実行時異常終了してしまう可能性があります。


■#elifと#errorを使った例(推奨)

char    *cpu[]={
    "Z80",
#if     CPU==3
    "Core i3"
#elif   CPU==5
    "Core i5"
#elif   CPU==7
    "Core i7"
#elif   CPU==9
    "Core i9"
#else
#error  "★未知のCPUはここでコンパイルエラーになる" 
#endif
};
#include <stdio.h>
int main(void){
    printf("%s\n",cpu[1]);
}

#elifと#errorを組み合わせると
予期せぬコンパイル状態となると
コンパイルエラーになってくれるので
間違いに直ぐ気が付きます。