ここでは、数値と文字列の相互変換ライブラリをご紹介します。
フルサイズのC(やC++)であれば、sprintf() や sscanf() で、かたづいてしまうお話ですが、まだまだマイコンなど小さなシステムでは、表示のために数値→文字列の変換をしたり、文字列として保存されているデータを数値に変換したりは、それなりの手間がかかります。
そんなわけで、マイコン用に作成した小さなライブラリです。
このライブラリも、無保証です。
ただし、ソースを示していますので、変更はご自由に行っていただいて結構です。
文字列と数値の相互変換を行います。
整数値のみに対応したものと、浮動小数点(というか、double 型)に対応したものの2セットがあります。
その処理系の、long 型までを取り扱います。
数値としてのオーバーフローや、文字列としての表示幅超過に対しては、何も対策を行っていません。
double 型と文字列の相互変換を行います。
ただし、取り扱えるのは、絶対値がその処理系の long に収まるもの
かつ、小数点以下の数値が(その数値を整数値としてみたときに) long に収まるものです。
指数形式には対応しておりません。
浮動小数点ライブラリでは、小数点の最下位桁に±1の誤差が発生する可能性があります。
必要なファイルは、
strnum.h(整数用・ヘッダファイル)
strnum.c(整数用・プログラム本体)
libfloat.h(浮動小数点用・ヘッダファイル)
libfloat.c(浮動小数点用・プログラム本体)
の4つです。
整数型のみで間に合う場合は、整数用の2つがあれば十分です。
浮動小数点を扱う場合には、(libfloat.c が strnum.c に依存しているので)すべて必要です。
概要は、strnum.h にコメントとして書き込まれていますが、以下の関数が使用可能です。
int isEqualStr(char *src, char *dest, int keta); /* keta の文字を比較して結果を返す Equal の時 1, not equal の時 0 */
Cの標準関数、strncmp() と同様の動きをします。
ただし、if(isEqualStr(buff, "TEST:", 5)) ... 等しいときの処理
のような使い方を想定していたため、strncmp() とは、返値が異なります。
void toStr(unsigned long v, char *buff, int keta, unsigned int radix); /* v を keta 桁の数値と見なして、buff の先頭から展開する */
数値を文字列に変換します。
char buff[10];
toStr(100, buff, 10, 16);
とすると、数値 100 を 16進数表現で、buff[0] 〜 buff[9] に展開します。
buff[] == {'0', '0', '0', '0', '0', '0', '0', '0', '6', '4'};
になります。
この段階では、先頭のゼロは残ったままです。
また、文字列の中間部分に固定幅のデータを挿入する用途からスタートしたため、変換した文字列にターミネータを付加しません。
ターミネータは、必要に応じてセットしてください。
void zeroSuppress(char *buff); /* buff を走査して先頭の0をスペースに置き換える */
先頭部分のゼロをスペースに置き換えます。
前項で処理した、buff[] に対して、
zeroSuppress(buff);
とすると、
buff[] == {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '6', '4'};
になります。
上記の、toStr() と zeroSuppress() を併用すると、数値を固定幅の文字列として表示する用途に使用できます。
unsigned long toNum(char *buff, int keta, int radix); /* buff の文字を、keta 桁の数値と見なして、数値化する */
こちらは、文字列を数値化する場合に使用します。
指定された位置から keta 文字を、radix で指定された文字表記と見なして数値化します。
char buff[] = {"0123ABCD"};
に対して、
toNum(buff, 4, 10) は、 "0123" を 10進表記と見なすので、123 という数値になります。
toNum(buff + 4, 4, 16) は、"ABCD" を 16進表記と見なすので、0xabcd = 43981 になります。
void makeString(char *src, char *dest, int keta); /* 16進文字列として表現された、src の keta 文字分(変換後の文字数で)を文字コードと見なして、dest に ASCII 展開する */
16進数表記の文字列を、文字コードと見なして、文字列に変換します。
char buff[10];
に対して、
makeString("616263646566", buff, 4); の結果は、
buff[] = {'a', 'b', 'c', 'd', ....} となります。
この場合、keta == 4 なので、4バイト分しか展開しません。また、ターミネータは付加しません。
void setStr(char *src, char *dest); /* src の文字列の '\0' までを ('\0' を含めて)dest にコピーする。 */
C標準関数の、strcpy() と同じ動きをします。
ただし、作者がモトローラ大好き少年だったため、src と dest が反対です。
void setStrN(char *src, char *dest, int keta); /* src の文字列の '\0' までを 最大 keta 文字の範囲で('\0' を含めて)dest にコピーする。 */
C標準関数の、strncpy() と同じ動きをします。
やはり、src と dest が反対です。
概要は、libflaot.h にコメントとして書き込まれていますが、以下の関数が使用可能です。
void toStrFloat(double value, char *buff, int up, int down); /* value を整数部分 up 桁、小数点以下 down 桁に展開する */
double 型の値を文字列に展開します。
char buff[32];
double v = 123.45
に対して、
toStrFlaot(v, buff, 4, 3); とすると、
buff[] = {' ', '1', '2', '3', '.', '4', '5', '0', ....};
toStrFlaot(v, buff, 2, 1); とすると、
buff[] = {''2', '3', '.', '4' ....};
となります。
この関数は、ゼロサプレスは(関数内部で)行いますが、ターミネータは付加しません。
double toNumFloat(char *buff); /* buff の文字列を数値と見なして、double 型に変換する */
文字列の先頭から、数値(および、'.' )と見なせる範囲を、浮動小数点表記と解釈して、double 型に変換します。
指数表記には対応しておりませんし、オーバーフローに対する対策も講じておりません
char buff[] = "123.45m";
toNumFloat(buff); は、123.45 という値を返します(m が数値ではないので、ここで処理が終わる)
複数のピリオドがある場合、最初のピリオドのみ小数点と解釈し、その以降は、「数値ではない」として処理対象から外します