priu8-not-work-in-stm32cubeide

STM32CubeIDE で PRIu8 が使えない

STM32CubeIDE 1.10.1 で作成した C 言語プログラムにおいて PRIu8 マクロや %hhu 書式指定子が使えないことが分かりました。また、その解決方法も分かりましたので記事にまとめてみました。

書式指定用のマクロ

標準ライブラリの inttypes.h には uint8_t のようなビット幅を指定した整数型のための書式指定マクロが定義されています。例えば uint8_t を 10 進数で表示する書式指定マクロは PRIu8 で、次のように使います。

uint8_t val;
printf("val = %" PRIu8 "\n", val);

PRIu8 のような書式指定マクロ1uintN_t の定義が異なる環境でも動くコードにするために用意されています。uint8_tunsigned char の別名として定義されている環境では %hhu を使いますし、unsigned short の別名である環境では %hu を使います。環境によって修正しなければなりませんが、PRIu8 を使っておけばコンパイルし直すだけで対応できます。

STM32CubeIDE での問題と解決方法

STM32CubeIDE で PRIu8 を使って printf を実行してみたところ、画面に val = hu と表示されてしまい、期待通りの結果が出ませんでした。inttypes.h が用意されており、かつ PRIu8 も定義されているのに、printf がそれを解釈できないという問題ですね。

原因はプログラムにリンクされる libc が組み込み用の簡易バージョンになっていることです。これをフルセットのライブラリを使うように変更することで、期待通りに動作するようになります。

設定はプロジェクト設定の C/C++ Build > Settings > MCU Settings の「Runtime library」にあります。Reduced C から Standard C に切り替えるとフルセットのライブラリに変更されます。

nano.specs とは

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)を使わないようなコードに変更するのも素晴らしい解決策だと思います。


作成:2022-09-23 09:36:44

最終更新:2022-09-23 09:36:44