C++ ⇒ VBA 書いて覚えるための初心者自己中記事

C++ ⇒ VBA 勉強の履歴を付けるというかノート代わりに使ってます

C++ #if 書いて覚えるための初心者自己中記事

コンパイルするかしないかを制御する。というお話。

 

 

if (array == NULL) {
	throw invalid_argument("Average に変な引数が渡されました");
}

仮に、プログラムのどこかでエラー判定があったとして。

デバッグ中はこのままで、その後は必要ない。

という場合。

 

そんな場合にはassert マクロ が良いと前に勉強した。

 

~~~~~~~~~~~~~~~~~~~~

assertマクロについて

デバッグ中だけチェックしたいチェック文があったら使う。

if 文の代わりにassert (  ); に条件式を書く。

false の場合はエラーの発生したファイル名と番号がわかる。

#include <cassert> で使える。

 

そしてこのassert を使った分はまとめて消すことが出来る。

方法は#include <cassert> より先に

#define NDEBUG

を定義すること。

~~~~~~~~~~~~~~~~~~~~

これから勉強するもので

同じようなことが出来るらしい。

 

 さっそく、

#if ! defined(NDEBUG)
	if (array == NULL) {
		throw invalid_argument("Average に変な引数が渡されました");
	}
#endif

 先頭に # が付いた文が二つ、さっきの if  文を囲っています。

 

この #if というやつはそのあとに書かれた条件が真(true) の場合のみ #endif までの範囲をコンパイルする、というもの。

 

definedは #if 専用の演算子

defined の後のカッコに書かれたマクロが定義されているかを判定する。

この場合は ! が付いているのでNDEBUG というマクロが定義されていたら

コンパイルしない、となる。

 

 

 よく似たもので二重インクルード防止コードがある。

#ifndef  マクロ名

#define  マクロ名

~~ヘッダファイルの内容~~

#endif

 

#ifndef は if not defined  もし定義されていなければ

#ifdef  は if defined  もし定義されていればというのもある

 

つまり、さっきのコードだと ! で逆にしていたけれど

# if defined (マクロ名) だったが

#ifndef を使うとすっきりする。

 

#ifndef NDEBUG
	if (array == NULL) {
		throw invalid_argument("Average に変な引数が渡されました");
	}
#endif

 このように定義されているかの判定が出来る。

さらに#if 関係は if なのでelse や else if なんかもある。

else は #else

else if は #elif

となる。

#ifdef マクロ名
~~処理~~
#elif defined(マクロ名)
~~処理~~
#else
~~処理~~
#endif

 #if の条件式で使用可能なのはコンパイル前に判明しているもの。

マクロや生の数値(即値というらしい) 。

 

 

#include <climits>
#define UINT32_MAX 0xFFFFFFFF
 
#if UINT_MAX == UINT32_MAX
typedef unsigned int Uint32
#elif ULONG_MAX == UINT32_MAX
typedef unsigned long Uint32
#elif USHRT_MAX == UINT32_MAX
typedef unsigned short Uint32
#elif UCHAR_MAX == UINT32_MAX
typedef unsigned char Uint32
#else
#error 32ビットの符号なし型が存在しません
#endif

はい、よくわからないの来ました。

#include <climits>

これは型の最大値のマクロが入っているんだろうなぁ。

 

#define UINT32_MAX 0xFFFFFFFF

これはなんだ・・?

記号定数の定義というやつなのね。

#define で UINT32_MAX という名前に0xFFFFFFFF という値に を付けている。

 

#if UINT_MAX == UINT32_MAX

ここで型の最大値との比較をしている。これはわかる。

 

typedef unsigned int Uint32

typedef は型に別名をつけるものだ。

UINT_MAXってのは unsigned int 型の最大値。

なので、unsigned int の最大値 == UINT32_MAX なのがtrue の時に

unsigned int に Uint32 という別名をつけたということか。

 

それを別の型でもやっているのね。

さいごに 

#error 32ビットの符号なし型が存在しません

#error は強制的にコンパイルエラーを出すものらしい。

 

0xFFFFFFFF

この数値が上限の unsigned 型は32ビットなのか・・・。

どういうことだろう。

32ビットということは2進数だと32桁ということだよね。

4進数で16桁

8進数で8桁

16進数で4桁・・・?

 

いやいやいやいや、

とても勘違いだわ。恥ずかしい。

 

16進数の1桁は4ビットなのか。

8進数の1桁は3ビットね。

 

だから4ビット分のが8桁あるから32ビットか。

 

本筋と関係ない箇所でつまづく。

いや、テキストの序盤にちゃんと記載してあった。

 

 

 話を戻して、32ビット符号なしの型を探して別名をつけるということをしているってことは、このコードの先ですでにその別名でいろいろやっているということか。

そんでコンパイルするときの環境に応じて32ビット符号なし型を適切に使うようにしていると。凄いなぁ。

こんなことが出来るなんて。

 

 

#ifdef NDEBUG
#define HOGE(a, b)
#else
#define HOGE(a, b) Debug::Hoge(a, b)
namespace Debug {
	void Hoge(int a, int b);
}
#endif

 この場合は NDEBUG を判定してデバッグモードとリリースモードで

#define HOGE(a , b) の中身を変えている。

 

 

#ifdef NDEBUG
#define DEBUG if(true){ }else
#else
#define DEBUG if(false){ }else
#endif

 こんな感じで中身の処理をさせるかさせないかとか。

 

#ifdef NDEBUG
#define DEBUG(body)
#else
#define DEBUG(body) body
#endif

 本文で DEBUG( 全部の処理 ) 

でやれば、すべてを使うか使わないかが行える。

 

 ここまで。