strtod(...) を使用して ASCII 文字列を double に変換する C コードがあります。このプログラムは、x86 (デバッグ)、ARM、および PowerPC (組み込みターゲット システム) 用にコンパイルされます。ARM ボードは、実際には利用可能な Debian を実行する BeagleBoard xM です。
strtod() が ARM/Debian システムで値を正しく変換しないことを発見しました。実際、私が試したすべての値は 0.000 でした。
実証するために、次の非常に単純なテスト プログラムを作成しました。
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, const char **argv)
{
const char myString[] = "123 ";
char *myEnd1 = NULL;
char *myEnd2 = NULL;
float fValue = 0;
double dValue = 0;
dValue = atof(myString);
printf( "Using atof():\n"
" String: %s\n"
" Double: %lf\n",
myString,
dValue );
fValue = strtof(myString, &myEnd1);
dValue = strtod(myString, &myEnd2);
printf( "Using strtof() / strtod():\n"
" String: %s\n"
" Float: %f (%d)\n"
" Double: %lf (%d)\n",
myString,
fValue, (myEnd1 - myString),
dValue, (myEnd2 - myString) );
return 0;
}
すべては、Ubuntu を実行している x86 PC (実際には仮想マシン内) でコンパイルされました。PowerPC および ARM コンパイル用のクロスコンパイラ ツールチェーンがあります。
x86 および PowerPC システムでは、出力は期待どおりです。つまり、次のようになります。
Using atof():
String: 123
Double: 123.000000
Using strtof() / strtod():
String: 123
Float: 123.000000 (3)
Double: 123.000000 (3)
ただし、BeagleBoard で実行すると、次のようになります。
Using atof():
String: 123
Double: 0.000000
Using strtof() / strtod():
String: 123
Float: -0.372039 (3)
Double: 0.000000 (3)
は???私は愚かなことを見逃しましたか?「myEnd」ポインターは、strtod() と strtof() が最初の非数値文字を検出したこと、つまり数値の末尾を検出したことを示すためにあることに注意してください。どちらの場合も数値の正しい文字数を報告しますが (3)、変換された値は間違っています。混乱する小数点がないので、ロケールの問題ではないと思います。
編集:
オプション「-static」を使用してテストプログラムを再コンパイルしました。もちろん、これによりバイナリははるかに大きくなりましたが、ターゲットの ARM プラットフォームで正しく動作するようになりました。
ライブラリの仕組みについて、私は少しぼんやりしています。また、クロス コンパイラ ツールチェーンをどのように構築したかを正確に思い出せません。おそらく、ターゲット ボードに実際にインストールされている Debian Linux と同じソースからビルドされたものではありません。
では、atof() などの不可解な動作は、動的にリンクされた実行可能ファイルによって「期待される」ライブラリが、システム上の実際のライブラリと同じではないことを意味しますか? これがより悪い問題を引き起こさなかったことに驚いています。このシステムを 1 年間運用してきましたが、これまでに遭遇した奇妙なバグはこれだけです。