デバッグ用printfでよく使うテクニックだが忘れがちなこと。
可変長引数のマクロ
- 引数の可変長部分を ... で表記する。
- 特別な識別子 __VA_ARGS__ が可変長引数に置換される。
#define DEBUG_PRINT(fmt, ...) printf(fmt, __VA_ARGS__)
可変長引数の関数
- stdarg.h をインクルードする。
- 引数の可変長部分を ... で表記する。
- va_list (可変長引数リスト)の変数を定義する。
- 可変長引数リストを使う範囲を va_start() と va_end() で囲む。
- va_start() の第2引数には、可変長引数の直前の引数を指定する。
(つまり、可変長引数のみをとる関数は作れない。) - ちなみに printf() の可変長引数リスト型版として vprintf() がある。
- また sprintf() の可変長引数リスト型版として vsprintf() がある。
void debug_print(char *fmt, ...) { va_list args; va_start(args , fmt); vprintf(fmt, args); va_end(args); }
デバッグ用printf
標準出力が使える環境であれば、可変長引数のマクロのみでOK。
#ifdef USE_DEBUG_PRINT #define DEBUG_PRINT(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DEBUG_PRINT(fmt, ...) /* 何もしない */ #endif
マイコン等で標準出力が使えない環境であれば、可変長引数の関数で実装する。
Arduino用の例を示す。(ボードによっては Serial.printf() が使える場合もあり。)
Debug.h
#pragma once #include <stdio.h> #include <stdarg.h> #ifdef USE_DEBUG_PRINT #define DEBUG_PRINT(fmt, ...) debug_print(fmt, __VA_ARGS__) #else #define DEBUG_PRINT(fmt, ...) #endif void debug_print(char *fmt, ...);
Debug.cpp
#include <Arduino.h> #include "Debug.h" void debug_print(char *fmt, ...) { static char buff[256]; // staticだとスレッドセーフでないことに注意 va_list args; va_start(args , fmt); vsprintf(buff, fmt, args); va_end(args); Serial.print(buff); }
使い方
#define USE_DEBUG_PRINT #include "Debug.h"
DEBUG_PRINT("hoge = %d\n", hoge);