how-to-deal-with-undefined-reference-to-__assert_func-ch32fun

undefined reference to __assert_func の対処法(ch32fun 編)

ch32fun(旧 ch32v003fun)での開発において assert マクロを使う場合、__assert_func が未定義だというエラーが出ることがあります。筆者が遭遇したエラーメッセージは次のようなものでした。

make build
《中略》
/usr/lib/gcc/riscv64-unknown-elf/13.2.0/../../../riscv64-unknown-elf/bin/ld: /tmp/ccdNAgAX.ltrans0.ltrans.o: in function `TIM1_SetPulseWidth':
/home/uchan/workspace/github.com/uchan-nos/eleclab/ch32v003fun_projects/ledtester2/periph.c:81:(.text.TIM1_SetPulseWidth+0x38): undefined reference to `__assert_func'

関数 TIM1_SetPulseWidth の中で assert マクロを使っていました。関数の実装を次に示します。

void TIM1_SetPulseWidth(uint8_t channel, uint16_t width) {
  switch (channel) {
  case 0: TIM1->CH1CVR = width; break;
  case 1: TIM1->CH2CVR = width; break;
  case 2: TIM1->CH3CVR = width; break;
  case 3: TIM1->CH4CVR = width; break;
  default: assert(0);
  }
}

引数 channel の値が想定外のときに assert で検出します。呼び出し元はこんな感じです。

TIM1_SetPulseWidth(led_current_ch, pw);

led_current_chuint8_t 型のグローバル変数です。

__assert_func の未定義エラーを回避するためには、この関数の定義をいずれかのソースコードに含める必要があります。筆者は次のような実装としました。

void __assert_func(const char *file, int line, const char *func, const char *expr) {
  printf("assertion failed inside %s (%s:%d): %s\n", func, file, line, expr);
  while (1) {
    __WFE();
  }
}

__assert_func を定義せずに assert が使える場合

assert に与えた式が真であると評価できる場合に __assert_func を呼び出すコードが省略されることがあります。この場合、そもそも __assert_func は呼び出されないので、定義する必要がありません。

この挙動は大きなメリットがあります。あえて __assert_func を未定義にしておくことで、assert の引数が偽になったことをリンクエラーとして検出できるのです。もし __assert_func を定義してしまっていると、リンクエラーにはならず、実行時にのみエラーが検出されます。実行してみないとプログラミングのミスに気付けないより、リンクエラーとして気付ける方がずっと嬉しいです。

これはコンパイラの最適化に頼った動作のため、必ずそうなるというわけではありません。試しに先述の関数呼び出しを次のように変えたところ、__assert_func の実装が不要になりました。

switch (led_current_ch) {
  case 0: TIM1_SetPulseWidth(0, pw); break;
  case 1: TIM1_SetPulseWidth(1, pw); break;
  case 2: TIM1_SetPulseWidth(2, pw); break;
  case 3: TIM1_SetPulseWidth(3, pw); break;
}

コンパイラは TIM1_SetPulseWidth の引数 channel が 0~3 のみだと分かると assert(0) が呼ばれることはないと判断できるわけです。assert の失敗をリンク時に検出するためだけに上記の様な冗長な書き方にしたいかというと、それは嫌ですけどね。



この記事を参照しているブログ内記事はありません。

作成:2025-05-16 04:58:56

最終更新:2025-05-16 04:58:56