Debug printf用の可変長引数マクロ
Cプログラマな方には既知だと思いますが、printfデバッグに便利なマクロ定義を発見したので備忘録も兼ねてポストします。
Printfデバッグとは
プログラムのデバッグのために、printf関数を使用して変数の内部状態をコンソールに表示したい場合があります。JTAGデバッグが使えないmbedやArduinoでは必須のテクニックです。今更言うまでもないですね。
デバック用マクロ
デバックが終了してプログラムをリリースする段階に進むと、デバック用のprintfは無効にしたいものです(printfは結構ROM/RAMを消費するなどMCU資源の無駄使いするため)。リリース時にいちちprintfをコメントアウトするのは面倒なので、Cのマクロを使って、デバック用のprintfを一括して無効化できると便利です。
Arduinoでは以下のマクロを定義していました。
#define DEBUG #ifdef DEBUG #define DEBUG_PRINTLN(x) Serial.println(x) #else #define DEBUG_PRINTLN(x) #endif
- プログラム中でDEBUG_PRINTLN(hoge)と書くと、4行目のマクロで Serial.println(hoge)に変換されます。
- 1行目をコメントアウトすると、DEBUG_PRINTLN(hoge)は空行に変換され、コンソール出力が無効になります。
Arduinoのように、print関数の引数が固定個数の場合は、この方法でもよいのですが、mbedやLPCXpressoのようにフルセットのprintfが使える場合、引数の数が可変長になるためうまくいきません。
で、マクロで可変長の引数を扱うための機能がないかと調べると、すぐに出てくるんですね。便利な時代だ。
可変長引数マクロ
__VA_ARGS__というパラメータを使うと、可変長引数をマクロ内で展開してくれます。mbedでの使い方はこんな感じです。
#include "mbed.h" #define DEBUG // Debug Macro #ifdef DEBUG #define DBG(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DBG(...) #endif int i = 0; int j = 1000; int main() { while(1) { i++; j--; printf("Loop: %d\n", i); DBG("Debug Print: i=%d j=%d\n", i, j); // DBG("Degub"); // Cause compiler error wait(1.0); } return 0; }
7行目の、...が可変長引数を示し、 __VA_ARGS__で実際の引数に展開します。
そのため、20行目のマクロは;
printf("Debug Print: i=%d j=%d\n", i, j);
に展開されます。
この方法では、引数を1つ以上指定しないと、マクロの展開後カンマが1つ残ってしまいコンパイルエラーになります。そのため、21行目のような使い方はできません。
LPCXpressoでは
LPCXpressoのIDEでは、Debugビルドを指定した場合、コンパイラの-DオプションにDEBUGが追加されるため、プログラム中で#define DEBUGを定義する必要はありません。
Releaseビルドに切り替えた場合、-DオプションからDEBUGが自動的に外れます。
おわりに
Cのマクロはコードの可読性が下がるので(特にネストしたマクロの場合)嫌いだったのですが、少し見直しました。ただ、引数をつけなかった場合のエラーの発生原因が直感的に分からないのはマクロの欠点ではあります。
参考資料:
- Object-Oriented & Java maneuver 別室 - 可変引数を取る関数(stdargs他)
- GCC - Variadic Macros
« LPCXpressoでCMSIS Peripheral Libraryを使う | トップページ | LPCXpresso LPC1769にMARY拡張基板を乗せる »
「mbed」カテゴリの記事
- mbed TY51822r3でmbed OSを使う(2016.04.16)
- mbed OSでLチカ(2015.11.22)
- 各種mbedのベンチマークテスト(2014.08.31)
- iPhoneからmbedをBluetooth LE (BTLE)で制御する(2013.02.11)
- Debug printf用の可変長引数マクロ(2011.04.29)
「NXP-ARM」カテゴリの記事
- LPCXpresso IDEでのC++コードサイズ肥大化の対策(2011.10.15)
- XBee APIモードライブラリのLPCXpressoへの移植(2011.10.09)
- LPCXpresso LPC1769でFree RTOSを使う(2011.07.27)
- LPCXpresso LPC1769でFatFsを動かす–USB Host編(2011.07.19)
- LPCXpresso LPC1769でFatFsを動かす - DMA編(2011.05.14)
コメント
この記事へのコメントは終了しました。
« LPCXpressoでCMSIS Peripheral Libraryを使う | トップページ | LPCXpresso LPC1769にMARY拡張基板を乗せる »
こんにちは
マクロの可変長引数機能はC99規格での拡張みたいですね。MS系のCコンパイラだとまだサポートされていないようでした。
C99より前は括弧を2重にするマクロを書いていました。
#define DBG(x) printf x
でDBG((fmt, a, b, c))はprintf (fmt, a, b, c)のように展開されることを利用したものです。
こんなやり方もあるということで^^
投稿: Sim | 2011年5月10日 (火) 07時06分
Simさんコメントありがとうございます。
なるほどこういうやり方もあるのですね。この方法だと、引数を取らない場合でもエラーにならない利点がありそう。(*^^)
投稿: todotani | 2011年5月10日 (火) 07時41分
こゆことじゃ?
#ifdef DEBUG
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...)
投稿: | 2016年7月 9日 (土) 09時46分