Help us understand the problem. What is going on with this article?

なにはともあれdbgprintfを定義しておくと便利、という話を丁寧に説明してみました。

C言語のお話。こんにちは、@island_peakです。本記事のゴールはコチラ。

  • ビルドを切り替えるだけで、不具合の原因を特定できるスマートな大人になれる
  • 可変長引数関数(printfなど)のマクロ定義方法(define)を理解できる
#define <stdio.h>
    dbgprintf("hello,printf debugging!"
        "(%d) as %s\n", hoge, test);

様々な開発ツールが登場している2019年。未だ、僕の中での最強のデバッグツールは、printfです。OSよりも低いレイヤーを開発していると、デバッガすら接続できない領域も多く 値(状態)を表示できる printf は必需品です。とはいえ常にデバッグ用のメッセージが出ているのもイマイチ…ということで見たいときだけ表示できるdbgprintfの実装方法を紹介いたします。
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3332393736332f38353761343337342d373035352d326432382d386666662d3562636136366162666435352e6a706567.jpeg

dbgprintfの定義方法 3種類

@island_peak がよく使うdbgprintfの実装パターンは、以下の3種類です。

  • ビルド時にON/OFFできるdbgprintf
  • 実行中にON/OFFできるdbgprintf
  • 実行中に指定したレベル以上のみを表示できるdbgprintf

ビルド時にON/OFFできるdbgprintf

C言語では#defineで可変長引数を使うことができます。#defineの置換元でf_, ...と書いておくと、置換後の文字列(f_), ##__VA_ARGS__で可変長部分を展開することができます。dbgprintfは開発時のみ使う機能のため、ON/OFFできるようにしましょう。#ifdefを使って#defineの置換方法を切り替えます。while(0){}何もしない処理です(アセンブラ命令レベルで処理が増えません)。

debug.h

#ifndef _DEBUG_H_
#define _DEBUG_H_

/* DEBUG = ON/OFF */
#define _DEBUG_PRINTF_

#ifdef _DEBUG_PRINTF_
#define dbgprintf(f_, ...) printf((f_), ##__VA_ARGS__)
#else
#define dbgprintf(f_, ...) while(0){}
#endif /* _DEBUG_PRINTF_ */

#endif /* _DEBUG_H_*/

スイッチアイコン0.png

実行中にON/OFFできるdbgprintf

先の例ではdbgprintfprintfに置換しましたが、while(条件式){... break;}に置換することにより、条件式にあわせてON/OFFできるプリント文を作ることができます。以下の例では、広域変数dbgOnにtrueが代入されている場合のみ出力されます。

debug.h

#ifndef _DEBUG_H_
#define _DEBUG_H_

/* DEBUG = ON/OFF */
#define _DEBUG_PRINTF_

#ifdef _DEBUG_PRINTF_
extern bool dbgOn;
#define dbgprintf(f_, ...) while(dbgOn){ printf((f_), ##__VA_ARGS__); break; }
#else
#define dbgprintf(f_, ...) while(0){}
#endif /* _DEBUG_PRINTF_ */

#endif /* _DEBUG_H_*/

ソースコード側

/** main.cなどに1回だけ定義する */
#ifdef _DEBUG_PRINTF_
bool dbgOn = true;
#endif /* _DEBUG_PRINTF_ */
    ...
    /** 使い方 */
    dbgprintf("ここはでます");
    ...
    dbgOn = false;
    dbgprintf("ここはでません");
    ...
    dbgOn = true;
    dbgprintf("ここはでます");

デバッガと併用する裏技

上例ではソースコードがdbgOntrueを代入した区間のみ表示する、と紹介しました。が、デバッガを接続しdbgOnの値を書き換えても表示のON/OFFができます。常にdbgOn=falseとし、不具合解析の際に自分で切り替えるという使い方も便利です。
スイッチアイコン.png

実行中に指定したレベル以上のみを表示できるdbgprintf

while(条件式){... break;}の条件式にtrue/falseだけでなく、数値比較を入れることにより、プリント文を変更することができます。下記のコードはdbgprintf(Lv, "hoge");のLvに従い、広域変数dbgLevelにあわせて出力を調整する例です。OSカーネルで利用されるprintkに似た機能を使うことができます。
スイッチアイコン2.png

debug.h

#ifndef _DEBUG_H_
#define _DEBUG_H_

/* DEBUG = ON/OFF */
#define _DEBUG_PRINTF_

#ifdef _DEBUG_PRINTF_
extern int dbgLevel;
#define dbgprintf(lv, f_, ...) while(dbgLevel<=lv){ printf((f_), ##__VA_ARGS__); break; }
#else
#define dbgprintf(lv, f_, ...) while(0){}
#endif /* _DEBUG_PRINTF_ */

#endif /* _DEBUG_H_ */

ソースコード側

/** main.cなどに1回だけ定義する */
#ifdef _DEBUG_PRINTF_
int dbgLevel = 0;
#endif /* _DEBUG_PRINTF_ */
    ...
    /** 使い方 */
    dbgprintf(1, "ここはでます");
    dbgprintf(2, "ここはでます");
    ...
    dbgLevel = 2;
    dbgprintf(1, "ここはでません");
    dbgprintf(2, "ここはでます");
    ...
    dbgLevel = 3;
    dbgprintf(1, "ここはでません");
    dbgprintf(2, "ここはでません");

まとめ

いかがだったでしょうか。小さい機能を試し書きする際など、手っ取り早く書くときはdbgprintfが便利です。すべてのコンパイラでビルドできる点もオススメポイントです。ではでは。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした