STM32CubeIDE 1.10.1 で作成した C 言語プログラムにおいて PRIu8
マクロや %hhu
書式指定子が使えないことが分かりました。また、その解決方法も分かりましたので記事にまとめてみました。
標準ライブラリの inttypes.h には uint8_t
のようなビット幅を指定した整数型のための書式指定マクロが定義されています。例えば uint8_t
を 10 進数で表示する書式指定マクロは PRIu8
で、次のように使います。
uint8_t val;
printf("val = %" PRIu8 "\n", val);
PRIu8
のような書式指定マクロ1は uintN_t
の定義が異なる環境でも動くコードにするために用意されています。uint8_t
が unsigned char
の別名として定義されている環境では %hhu
を使いますし、unsigned short
の別名である環境では %hu
を使います。環境によって修正しなければなりませんが、PRIu8
を使っておけばコンパイルし直すだけで対応できます。
STM32CubeIDE で PRIu8
を使って printf
を実行してみたところ、画面に val = hu
と表示されてしまい、期待通りの結果が出ませんでした。inttypes.h が用意されており、かつ PRIu8
も定義されているのに、printf
がそれを解釈できないという問題ですね。
原因はプログラムにリンクされる libc が組み込み用の簡易バージョンになっていることです。これをフルセットのライブラリを使うように変更することで、期待通りに動作するようになります。
設定はプロジェクト設定の C/C++ Build > Settings > MCU Settings の「Runtime library」にあります。Reduced C から Standard C に切り替えるとフルセットのライブラリに変更されます。
Reduced C に書いてある「--specs=nano.specs」を頼りに調べてみると、どうやら Reduced C とは Newlib-nano のことのようです2。Newlib の nano-vfprintf.c を読んでみると、確かに %hhu
には対応してない雰囲気です。一方で vfprintf.c には h
が連続する場合のコードが実装されており、nano 版の実装とは明らかに差がありますね。
printf
系統の関数は非常に高機能ですが、よく使う機能はごく一部です。私が PRIu8
を使おうとしたのは今回が初めてです。そういう事情があり、プログラムサイズの制約が厳しい組み込み向けでは機能を削減した C ライブラリが使われるのですね。Standard C にするとフルセットにはなりますがプログラムサイズは増えますので、PRIu8
(あるいは %hhu
)を使わないようなコードに変更するのも素晴らしい解決策だと思います。
nano.specs
defines the system include path and library parameters to use newlib-nano." とあります。