ESP32でFemtoRuby

以前、raspberry pi picoでPicoRubyを動かしてみたことがあるが、その時にはESP32では動かす方法が見付からなかった。 ESP32では、mruby/cベースのFemtoRubyを使うらしく、それを簡単に使う方法を見付けたので、少し試してみた。 以前はPicoRubyと読んでいたものを、FemtoRubyと呼ぶことにしたらしく、名前が混在していてよく分からないこともある。

ESP32への書き込みは、 Webインストーラー を使って行う。Chromiumでこのサイトに行って、ESP32を繋いで書き込みを行う。 Webからこんなことが出来るようになっているのかと関心した。 別のモジュールで試したら、書き込みに失敗したりしたけど、うまくいったやつで、少し使ってみた。 書き込みは53%から一気に100%になって、不安だったが大丈夫のようだ。

今度は<a href=“https://picoruby.org/terminal>Webターミナルに行って、connectを押してから、リターンキーを何度か押したら、Shellが立ち上がった。 irbと打ったらrubyが使えるようになる。 GPIOを使ってみたら、無事に動いた。 次はADCかなと思ったら、require ‘adc’としないといけないようだ。 その次はPWMを試したら、require ‘pwm’まではできたが、PWM.newしたら、エラーでリセットがかかってしまった。

使えないボードがあったり、エラーでリセットがかかったりと、まだ不安定なようだが、手軽に使えるようになって来ているようだ。 私もESP32でArduinoを使ってmruby/cを動かしているが、その情報を公開する価値があるかどうか迷っている。 ESP8266でmruby/cを使っている人はあまりいないようで、情報が少かったので、このブログにも書いたこともあるし、ホームページにもまとめておいたので、誰かが使ってくれるかも知れない。

Read more...

ch32funのMakefile

ch32funで作ったプログラムのmapファイルを見ていたら,使っていないはずの関数が残っていたので,なんでだろうと思って調べてみたら,Makefileのオプションの指定が間違っていたことが分かった.

別のフォルダにあるライブラリも含めないといけなかったので,それをMakefile中のCFLAGSで指定し, さらに最適化して使っていない関数を除去しようと,以下のように指定していた.

CFLAGS += -Os -flto

理由はよく理解していないが,さらに以下のオプションを加えないと,使っていない関数が適切に除去できなかった.

CFLAGS += -ffunction-sections -fdata-sections

ch32funのexampleの多くでは,これらのオプションの指定はしていない. 調べてみると,ch32fun.mkの中では,以下のような記述がある.

CFLAGS?=-g -Os -flto -ffunction-sections -fdata-sections -fmessage-length=0 -msmall-data-limit=8 -fno-tree-loop-distribute-patterns

しかし,Makefile中でCFLAGSの設定したことによって,この設定が無効になってしまったようだ. Makefileで,ライブラリについての情報はEXTRA_CFLAGSに書くようにして,CFLAGSを指定しないしないようにしたら,期待通りの結果が得られた.

Read more...

mruby/cの表示ルーチンの改良

mruby/cには,表示をするやり方が複数ある. ruby側からは,p,puts,print,printfなどがあり, C言語からもいくつもの表示方法がある. ruby側から表示する関数は,c_object.cの中で定義されているが, p,puts,printでは,対応するC言語側の関数を呼び出しているのに対して, printfはsprintfを通して,mrbc_printf_intやmrbc_printf_floatを呼び出している. C言語から表示する関数は,console.cの中で定義されており, mrbc_print,mrbc_printfなどを使って表示することになっているが, 整数の場合にはmrbc_printf_intで, 浮動小数の場合にはmrbc_printf_floatとmrbc_format_floatで整形されている. 整数を扱うmrbc_printf_intでは,整数を適切に整形するプログラムが書かれているが,負の数でゼロ埋めをする際の処理に軽微なバグがあることを,2026/6/29のブログで紹介した. 一方,浮動小数を扱うmrbc_printf_floatとmrbc_format_floatでは, 共に整形の部分はsnprintfに丸投げしている. この関数は,非常にコンパイルサイズが大きく,mruby/cにFloatを組み込んだときに大きくなる一つの要因になっていると思われる. 小数はC言語のライブラリを使って整形しているのに,整数はmruby/cでコード書いているのは,Floatを無効にしたときに,整数を整形できるようにするためであろうが,Floatを使う際には整数の整形ルーチンがダブってしまい,無駄が多い. そこで,小数の整形をするルーチンを独自に書き下して,snprintfを使わないようにすれば,Floatを組み込む際にも,それほど大きくならないように出来るかも知れない. また,ch32funのsnprintfでは小数は表示できないので,Floatの表示ができないが,その問題も解消できる. mrbc_format_floatは,value.cの中で定義されているが, その中のsnprintfはmrbc_snprintfに変更することができる. console.cの中で定義されているmrbc_printf_floatは, mrbc_snprintfで使われているので, 元の関数はmrbc_format_float2と名前を変えて, mrbc_printf_floatを新たに定義することにした. Floatの表示は,通常の小数表記,科学的な表記,自動判定の3つの方法があり,これらはそれぞれ’f’,’e’,‘g’で表され,大文字を使う’E’と’G’もある. これらの表示をするためには,どのような処理が必要かを考えると,整数部と小数点以下を分離して桁数などに応じての表示と,指数部と仮数部の計算などをしなければならないことが分かる. 指数部は,自動判定時の小数表記と科学的表記の分岐にも使われる. そこで,通常の小数を表示する関数と,指数部と仮数部を計算してそのまま科学的表記をするか先の関数を呼び出して小数の表示をする関数の2つの関数を定義し,mrbc_format_floatからは指定に応じてこれらの2つの関数を呼び出すことにした. 通常の小数を表示する関数では,絶対値に直してから,その整数部分と精度を考慮した小数部を,整数として求めて,小数点を挟んでそれらをそれぞれmrbc_printf_intを用いて表示すれば良い. 前者は必要なら符号も表示し,後者は精度の幅でゼロ埋めして表示する. この関数は,科学的な表記の仮数部分を表示するときに呼び出すが,四捨五入で繰り上がりが生じて桁が変わる場合には,仮数を桁を調整しなければならないので,科学表記のときにはそのための処理も行うようにした. この関数を定義するときに,できるだけサイズを小さくするために,効果が大きな2つの工夫を行った. 1つ目の工夫は整数部と小数部に分ける際に,小数点の位置を精度の分だけ下にずらしてから四捨五入のために0.5を足した後で,うまくその2つの部分を取り出したことである. 単精度のときには,全体を整数に変換して,その上位の整数部と下位の小数部を割り算を用いて計算すると,32bitのCPUで扱いやすく,サイズを抑えることができた. 倍精度のときには,整数部は小数点の位置を戻して整数化して取り出し,小数部は整数部の桁数をずらして引くことによって取り出すと,小さくすることができた. 両者で小さくなるようなアルゴリズムが違うのは奇妙な気もする. しかしこのやり方では,整数部や精度が大き過ぎる場合には,問題が起こる可能性もあることに注意が必要である. 2つ目の工夫は,符号と絶対値を求める際に,専用の関数を使ったことである. 単にx<0や-xを計算するだけなら,バイナリでも単純になると思っていたのだが,doubleでは複雑な処理が行われるらしく,math.hを組み込んで,signbitとfabsを使うことで,100バイト以上小さくなった. 指数部の計算などをする関数では,絶対値に直してから,仮数xが1<=x<10になるまで,10を掛けたり割ったりして,同時に指数部を数える. そして,表示方法を自動判定するときには,精度と指数から判定して,小数表記なら先の関数を呼び出して,科学表記なら仮数を同様に表示して指数部は整数として表示する. この関数でも,doubleの処理の部分を工夫することが重要である. 絶対値を取る部分は,先と同様にも処理できるが,1.0や10.0との比較する部分を小さくするために,doubleをuint64_tとして解釈して,処理することにした. 正の数の場合には,doubleの大小とuint64_tの大小が一致することを利用して,大小を判定した方が,コンパイルサイズが小さくなったので,そのようにすることにした. それに伴って,絶対値や符号の処理はbit演算で表した. ソースの可読性が下がるという欠点はあるが,コンパクトにするためには仕方ないだろう. これで,浮動小数点も表示できるようになったが, 精度を指定しなかったときには,それが0になるようになっており, そうすると,printf “%f”,3.14としても,3しか表示さらなくなってしまった. 精度が0のときには,6にするようにすると,今度は精度を0にできなくなってしまう. そこで,精度を指定しなかったときの値を-1にした. そのために,関数mrbc_printf_mainの中でpf->fmtが初期化された直後に-1を代入する. pf->fmt.precision=-1; そして,ピリオドがあったら,その値を0にして,精度を取り込む. pf->fmt.precision=0; しかし, pf->fmt.precisionが0で無い場合に,精度が定義されているという判断をしている箇所が, mrbc_printf_bstrとmrbc_printf_intの中に見つかったので, それらの条件を以下のように書き換えた. pf->fmt.precision > 0 この修正により,デフォルトの表示の精度の問題も無くなり,思った通りに表示できるようになった. snprintfを使っていた場合には,フォーマットの文字列もこの関数で処理されるので,この問題は生じていなかったのである. console.cにこれらの修正をした後に,その末尾に先に考えた以下のコードを追加すれば, 新たなmrbc_print_floatが定義される. #if MRBC_USE_FLOAT #include <math.h> static void mrbc_printf_f(mrbc_printf_t *pf, double value, int *exponent) { int is_negative = signbit(value); value=fabs(value); int precision = pf->fmt.
Read more...

ch32funのfsusb

WCH社のマイコンでmruby/cを使うときなどに、ch32funを使っているのだが、 いつの間にかUSB部分のファイルが更新されたようだ。 github上のプログラムを利用するときには、できるだけreleaseを使うようにしており、そうするとファイルの内容は変更されない。 しかし、ch32funについては、最新のreleaseが一年半以上前のもので、CH32X035などの新しいマイコンを使うこともあるので、github上の最新のファイルを使っている。 普段は、以前downloadしているzipを使って作業をしていたので気付かなかったが、新たにdownloadしたら私のプログラムがコンパイル出来無くなっていたので、原因を調べたら、私が参照しているファイルが更新されたことが原因だった。

CH32X035でUSBを使うために、ch32funのfsusbを使っている。 このファイルは二週間前に更新されており、その仕様が変更になった。 以前と同じようにコンパイルしたら、fsusbで定義されている関数が参照できないというエラーが出て、原因が分からずにしばらく苦労していたが、 ADDITIONAL_C_FILESで指定しないといけなくなったことに気が付いた。 さらにエラーが出たが、それは変数や関数の名称が変更になっていたためであることも分かった。 これらに対応して、修正を加えたら、コンパイルは通るようになった。 追って、動作確認をしてみようと思う。

プログラムを安定して使うためには、やはりreleaseを使った方が良いことを実感したが、ch32funの新しいreleaseが早く出ないかな。

Read more...

ArduinoでCH32V203の隠しflash

CH32V203は、公式のflashは64kであるが、低速のflashが160kあり、 Arduinoからこれを利用する方法は2026/5/17のブログに書いたが、その手法は少し手間がかかった。 それを少し簡単にする方法を見出したので、紹介したい。 まず、160kのflashの情報をLink.ldに記述するのだが、ch32funでの記述を参考にして、EXTという名称にすることにした。 そして、EXTにはrodataを格納することにする。 そのように変更するためのシェルスクリプトは以下の通りである。 cd ~/.arduino15/packages/WCH/hardware/ch32v/1.0.4/system/CH32V20x/SRC/Ld/ sed -i -e 's/\r/\n/g' Link.ld sed -i -e 's@FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K@FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K\n\tEXT (rx) : ORIGIN = 0x08010000, LENGTH = 160K@' -e '/[.]rodata/d' -e 's@\.fini @.storage :\n{\n. = ALIGN(4);\n*(.rodata)\n*(.rodata*)\n. = ALIGN(4);\n} >EXT AT>EXT\n\n\t.fini @' Link.ld 以前に紹介した方法では、スケッチをコンパイルした後で、 通常のflashとEXTに書き込むバイナリを取り出す必要があったのだが、 platform.txtをいじると、これを自動で出来るようにすることができる。 バイナリを保存するように指定したときに、flashとEXTについて、バイナリを取り出して64kになるようにして、スケッチのあるフォルダにコピーするように、するのである。 その設定のためのシェルスクリプトは以下の通りである。 cd ~/.arduino15/packages/WCH/hardware/ch32v/1.0.4/ sed -i -e 's@recipe.objcopy.bin.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin"@recipe.objcopy.bin.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.
Read more...

mruby/cでタイムスタンプを取得

mruby/cを用いて、ある信号のモニタをしようと思ったのだが、それには時間に対して信号がどうなっているのかを記録する必要があった。 しかし、mruby/cでは、sleepなどはできるが、現在の時間を取得することはできない。 arduinoだと、micros()で起動してからの時間がマイクロ秒単位で取得できるのだが、これに相当する機能をmruby/cに実装することにした。

まず、methodの名前をどうするかを悩んだが、ticks_usとすることにした。 mruby/cの整数はdefaultでは32bitなので、一時間と少しで零に戻ることになるが、通常は問題無いだろう。 整数を64bitにもできるが、メモリを食うので、 32bitのままで使うことにした。 ch32funでこれを実現するには、micros()に対応する関数は無いが、クロックを数える関数があるので、何クロックがマイクロ秒に対応するかを考えれば良い。 mruby/c用に、ch32funでマイクロ秒単位のタイムスタンプを返す関数を以下のように定義した。

static void c_ticks_us(mrbc_vm *vm, mrbc_value v[], int argc){
  SET_INT_RETURN( funSysTick64()/DELAY_US_TIME );
}

あとは、これをmethodとして定義すれば、rubyから使えるようになる。

mrbc_define_method(0, 0, "ticks_us", c_ticks_us);

しかし、この機能を組込んでコンパイルしたら、1k以上も大きくなってしまった。 今回は時間が必須なので仕方無いが、通常はこの機能は組込まないで良いだろう。

ch32x035を使って、

while true
  printf "%d\r\n",ticks_us
  sleep_ms 1
  printf "%d\r\n",ticks_us
  sleep 1
end

を実行したら、2.1msぐらいの時間が消費されていた。 10msだけsleepするようにしたら11.1msぐらいかかったので、 sleepの前後の処理と表示する部分で1msぐらいかかっているようだ。

二つの信号の変化があったときに、その時間とピンの状態を表示するために、 以下のようなプログラムを走らせてみた。

green=GPIO.new(25,GPIO::IN)
blue=GPIO.new(35,GPIO::IN)
pg=0
pb=0
while true
  g=green.read
  b=blue.read
  next if pg==g and pb==b
  printf("%d,%d,%d\r\n",ticks_us,pg=g,pb=b)
end

これを使って信号をモニタしたところ、 ある信号は約500マイクロ秒で変化したように表示されるので、表示自体はそれ以下の時間で行われているようだ。 表示時間を考慮するならば、信号を一旦は配列にためておいて、まとめて表示すると良いかも知れない。

Read more...

mruby/cのStringを無効化した状態でUART

mruby/cでStringを無効化することができるようになった。 私が最近いじっているch32funを用いたCH32X035用の環境では、Stringが無いとそのままではI2CやSPIは動かなかったが、 出力はmake_output_bufferでStringを使わないようにして、 入力は文字列を整数の配列に変換することにより、動くようになった。 しかし、入出力ともにStringであるUARTは動かせていなかった。 APIのガイドラインとは異なる仕様になるが、UARTの入出力もI2CやSPIと同様の処理をすれば、String無しでもUARTを使えるようになるはずである。 今回はそのやり方について考えてみたい。

I2CやSPIでは、マイコンはセンサーなどのICと通信し、やり取りされるデータは数値であることが多い。 一方UARTでは、通信相手はPCや別のマイコンで、文字列をやり取りすることも多い。 それゆえに、UARTの入出力でStringを使うようになっているのだろう。 Stringを無効にした場合には、当然Stringは使えないが、Symbolを使えば限定的ではあるが文字列を扱うことができる。 そこで、 make_output_bufferでSymbolも使えるようにして、それをUARTの出力用に使うと良いと考えた。 UARTで出力するときには、通常はStringが引数として与えられるが、make_output_bufferはStringも受け付けることができるので、UARTでも問題無く動作する。 Stringを無効にしたときも考慮して、数値や数値の配列に加えて、Symbolを使って、出力すべきデータを指定するのである。 入力では、それをSymbolに変換することは可能であるが、mruby/cのSymbolには、GCが働かないようなので、様々なデータを受け付けたてSymbolに変換すると、メモリが圧迫されてしまう。 I2CやSPIと同様に、入力されたデータは数値の配列にするしか無いだろう。

Stringを無効にした このような限定的な仕様にしたときに、UARTが何の程度の実用性があるかを、 例えば標準入出力とUARTのコンバーターが作れるかを考えてみよう。 標準入力は、getbyteで数値として受け取るので、それを数値としてUARTで出力すれば良い。 UARTからの入力は、数値の配列となるが、数値はprintfで%cを指定すれば、文字として標準出力に出すことができる。 つまり、Stringが無くても、コンバーターが作れることが分かる。

mruby/cの コンパイルサイズを小さくするには、使わないAPIを組み込まないという方法もあるが、様々な状況に対応して、ソースを書き換えるのは面倒である。 それに対して、FloatやStringを無効にするのは、vm_config.hの中の指定を変更するだけで良い。 CH32X035用の環境では、Floatをすでに無効にしていたが、 さらにStringを無効にすると約10kバイト小さくなり、 String以外のmrblibを組み込んでも、 flashに10k以上の余裕ができる。 それだけあれば、かなり複雑なrubyのプログラムも組み込むことができる。 Stringを使って手軽に小さなプログラムを使う場合と、Stringを使わずに比較的大きなプログラムを作る場合用に、二種類のbinaryを用意しておけば、本体をコンパイルする必要はなく、mrbcだけ作って、binaryと結合して書き込めば良いので、便利だと思う。

Read more...

mruby/cでStringを無効化

mruby/cをコンパイルしたときのサイズを小さくするには、いくつかの方法がある。 その中で、mruby/cの設計段階から想定されている方法が、FloatまたはStringを無効にする方法である。 FloatやStringを無効にするオプションの指定は、vm_config.hにで定義されているだが、3.4.1や4.0.0などのリリースでは、そのままでは動かない。 Floatについては自分でファイルを変更して対応していたが、Stringについてはどこをいじるべきか分らずに、放置していた。 しかし、github上ではつい最近これらの問題に対する対策がされたようである。 そこで、それを参考にしてmruby/cをStringを削除して使ってみた。 検証は、最近いじっているch32fun上のCH32X035用の環境で行った。 Taskは消しているので、mruby/cのそれ以外の部分を、Stringを無効にしても大丈夫なように修正するシェルスクリプトは以下のようになった。 awk '/MRBC_CLASS\(String/{$0="#if MRBC_USE_STRING\n"$0"\n#else\n 0,\n#endif"}1' class.c >temp.tmp && mv temp.tmp class.c cat c_object.c |awk '/void mrbc_object_inspect/{$0="#if MRBC_USE_STRING\n"$0;a=1}a&&/^}/{$0=$0"\n#endif";a=0}1' |awk '/static int set_sym_name_by_id/{$0="#if MRBC_USE_STRING\n"$0;a=1}a&&/^}/{$0=$0"\n#endif";a=0}1' >temp.tmp && mv temp.tmp c_object.c cat c_object.h |awk '/void mrbc_object_inspect/{$0="#if MRBC_USE_STRING\n"$0"\n#endif"}1' >temp.tmp && mv temp.tmp c_object.h cat error.c |awk '/static void c_exception_message/{$0="#if MRBC_USE_STRING\n"$0;a=1}a&&/^}/{$0=$0"\n#endif";a=0}1' |awk '/TT_STRING/{$0="#if MRBC_USE_STRING\n"$0;a=1}a&&/}/{$0=$0"\n#endif";a=0;b=1}b&&/}$/{$0="#if MRBC_USE_STRING\n"$0"\n#endif";b=0}1' |awk '/c_exception_message /{$0="#if MRBC_USE_STRING\n"$0"\n#endif"}1' >temp.tmp && mv temp.tmp error.c cat _autogen_class_exception.h |awk '/c_exception_message/{$0="#if MRBC_USE_STRING\n"$0"\n#endif"}1' >temp.
Read more...

mruby/c 4.0.0のリリース

mruby/c 4.0.0がリリースされていたので、3.4.1との違いをざっと調べてみた。 機能の点では、mrbcで生成されるバイトコードの対応するversionが変わったのが最も大きな違いだが、いくつかのmethodが追加されている。 機能とはあまり関係ないところでは、struct VMがmrbc_vmに、halがmrbc_halに名称が変わったり、小数への変換に使われていたatofが、floatかdoubleによってstrtofかstrtodに変更になったりしていた。

最近はmruby/cの3.4.1をch32funでコンパイルしていたが、それを多少修正して、4.0.0をコンパイルしてみた。 Floatは使えなくして、Taskとmrblibも除いた状態で比較して、1.6k大きくなっていた。 新しいmethodなどが増えると、どうしても大きくなってしまうのは仕方無いことではあるが、サイズはあまり増加しないで欲しいものである。 先日のブログで、console.cなどのファイルを修正すると、約0.4k減ることを紹介したが、これを適応すると、59kとなった。 ch32x035だとユーザーが使えるのは3kということになる。 このくらいあれば、なんとか使えるレベルかな。 でも、さらにmethodが増えると、容量が厳しくなるだろう。

vm_config.hの中には、FloatやStringをoffにする指定があるのだが、そのままではコンパイルできなかった。 4.0.0でも、同じ状況ではあったが、github上では、これらに対する修正が加わったようなので、次のリリースではそのままでFloatやStringをoffにできるようになるだろう。 Stringをoffにすると、大幅にサイズが小さくなるだろうから、flashの容量が厳しいときには、そうして使うと良いだろう。

Read more...

mruby/cのprintfの問題点

mruby/cをいじっていて気が付いたのだが、 そのprintfには二つの問題点があるように思われる。 その一つは、C言語からはprintf("%o",16)が使えないことである。 C言語からは八進数は使っていないので、加えてないのかも知れないが、二進数も使っていないのに、コードには書かれているので、加え忘れなのではないかと思う。 もう一つは、例えばprintf("%04d",-3)とすると、-003ではなく、00-3となるということである。 前者が正しいのだが、整数を文字列に変換してから、長さを調整しているので、このようになってしまうようだ。 これらを修正してみたので、ここでその解説をする。 mruby/cでは、printfについての関数はconsole.cで定義されている。 その最初の関数で"%d"などのフォーマットの文字によって、分岐する部分があるのだが、 ここに以下の記述を加えると、最初の問題は解決する。 case 'o': ret = mrbc_printf_bit( pf, va_arg(*ap, unsigned int), 3); break; しかし、bとoとxで三回も同じ関数が呼び出されていて、効率が悪く、これを加えると、私の環境でコンパイルすると12バイト大きくなった。 そこで、これらをまとめて、以下のように一つにすると、最初より8バイト小さくなって、八進数にも対応できるようになる。 case 'b': case 'B': case 'o': case 'x': case 'X': ret = mrbc_printf_bit( pf, va_arg(*ap, unsigned int), pf->fmt.type*9/2%8); // 1,3,4 for b/B,o,x/X break; 他にも、以下のような数式を考えたのだが、括弧が無くて読み易いので上のコードを採用した。 (pf->fmt.type&89)%7 (pf->fmt.type&0xdf)/7-8 ちなみに、c_object.cには、rubyのprintf用のc_object_sprintfという関数があって、その中では八進数に対応するコードはあるが、これを同様にまとめるように変更すると、70バイト程小さくなった。 これらの似た処理をうまく共通化できたら、さらに効率が良いのだけど。 しかし、C言語から呼び出す関数とruby用の関数では、型のチェックなどの処理の違いがあり、完全な共通化が難しいようである。 次の問題を解消するには、console.c中のmrbc_printf_int中の処理を変更する必要がある。 その処理の仕方を見てみると、 整数を文字列に変換して、別に長さを調整する文字列を用意して、そこに符号と精度の調整の0を追加して、整数の文字列を追加するという過程を取っている。 0で長さを調整した後で、符号が加わるのが問題なのである。 できるだけ変更が少なくて、思うような挙動をするにはどうしたら良いかを考えたが、0で長さを調整する場合には、精度を変更してしまえば良いということを思い付いた。 そうするには、pad_widthを定義しているところの次に、以下の行を加えると、ほぼ予定通りの挙動をするようになる。 if(pf->fmt.flag_zero && pf->fmt.precision<pad_width) pf->fmt.precision=pad_width; 長さと精度の両方を指定したときの挙動は、rubyとは若干違うかも知れないが、大きな問題では無いだろう。 しかし、この変更で、24バイトも大きくなってしまった。 さらにconsole.cの中を眺めていたら、以下の記述に目が止まった。 buf[2] = "0123456789ABCDEF"[uch >> 4]; buf[3] = "
Read more...