条件付きコンパイル②
今回も条件付きコンパイルの詳細を見ていきましょう。
例2.否定
#include <stdio.h> #define YELLOW 0 #define BLUE 1 #define LED //#define GREEN void func(int num){ printf("%d\n", num); } int main(){ /* 否定 */ #if !YELLOW //真 func(11); #endif //#if !LED // fatal error C1017: 整数定数式が無効です。 // func(12); //#endif #if !(YELLOW) //真 func(13); #endif #ifndef YELLOW //偽 func(14); #endif //#ifndef (YELLOW) //fatal error C1016: #if[n]def は、識別子を必要とします。 // func(15); //#endif #if !defined YELLOW //偽 func(16); #endif #if !defined (YELLOW) //偽 func(17); #endif #if !defined (LED) //偽 func(18); #endif #if !defined (GREEN) //真 func(19); #endif }
ここでのポイントは#ifndef と 否定演算子! の使い方になります。 #if !(YELLOW) と書いた場合はYELLOWの値の否定なので真となります。対して #ifndef YELLOWと書いた場合はYELLOWという文字列が定義されているので、その否定となり偽となります。同様に#if !defined (YELLOW)も文字列は定義されているので、その否定となり偽となります。なお#if defined !(YELLOW) とはかけません。defined で修飾されたシンボルはただのシンボルであり定義された数値は評価されません。 否定演算子!はオペランド(被演算子)に真偽値 しかとれませんので、シンボルを修飾することはできません。この事からわかるようにdefined (シンボル) の戻り値は真偽値に他なりません。なお否定演算子!は見ずらいので忌避されます。僕の経験で言うと基本的には条件付きコンパイルでは否定を使わず#elseを使います。インクルードガードの時だけ汚くなるので#ifndefを使います。
まとめ
①#if は続く値が真偽値なので否定演算子!で否定できる。
②#ifdef, defined は続く値がシンボルなので否定演算子!で否定できない。
③否定は見ずらく真偽を勘違いしやすいのであまり使わない。
④#ifndefはインクルードガードで使う。