ANSI C のみを使用して、C スタイルの文字列が整数または実数 (つまり、float/double) であるかどうかをかなり確実に判断する最良の方法は何ですか?
9 に答える
これらの関数は失敗すると 0 を返すため、atoi と atof を使用しないでください。前回チェックしたとき、0 は有効な整数と浮動小数点であるため、型の決定には使用できません。
strto{l,ul,ull,ll,d} 関数を使用します。これらは失敗時に errno を設定し、変換されたデータが終了した場所も報告します。
strtoul: http://www.opengroup.org/onlinepubs/007908799/xsh/strtoul.html
この例では、変換する単一の値が文字列に含まれていると想定しています。
#include <errno.h>
char* to_convert = "some string";
char* p = to_convert;
errno = 0;
unsigned long val = strtoul(to_convert, &p, 10);
if (errno != 0)
// conversion failed (EINVAL, ERANGE)
if (to_convert == p)
// conversion failed (no characters consumed)
if (*p != 0)
// conversion failed (trailing data)
最初に errno を 0 に設定するのを忘れていたことを指摘してくれた Jonathan Leffler に感謝します。
sscanfを使用すると、atoi および atof ソリューションの場合のように、文字列が float か int かどうかを特定できます。
コード例を次に示します。
int i;
float f;
if(sscanf(str, "%d", &i) != 0) //It's an int.
...
if(sscanf(str "%f", &f) != 0) //It's a float.
...
atoi および atof は、変換できない場合は 0 を変換または返します。
strto{l,ul,ull,ll,d} 関数が最善の方法であるという Patrick_O に同意します。ただし、注意すべき点がいくつかあります。
- 関数を呼び出す前に errno をゼロに設定します。あなたのためにそれを行う機能はありません。
- リンク先の Open Group ページ (Patrick もリンクしていることに気付く前に私がアクセスしたページ) は、errno が設定されていない可能性があることを指摘しています。値が範囲外の場合は ERANGE に設定されます。引数が無効な場合は、EINVAL に設定される場合があります (ただし、設定されない場合もあります)。
当面の仕事によっては、返された変換ポインターの末尾から末尾の空白をスキップするように手配し、最後の文字が終端の null '\0' でない場合は不平を言う (拒否する) ことがあります。または、だらしなく最後にガベージを表示するか、キロバイト、メガバイト、ギガバイト、テラバイトなどの「K」、「M」、「G」、「T」などのオプションの乗数を受け入れることができます。コンテキストに基づく要件。
strtol/strtoll (atoi ではない) を使用して整数をチェックします。double をチェックするには、strtof/strtod (atof ではない) を使用します。
atoi と atof は文字列の最初の部分を変換しますが、文字列全体を使用したかどうかはわかりません。strtol/strtod は、文字が変換された後に余分ながらくたがあったかどうかを示します。
したがって、どちらの場合も、null 以外の TAIL パラメータを渡して、文字列の末尾を指していることを確認してください (つまり、**TAIL == 0)。また、アンダーフローとオーバーフローの戻り値も確認してください (詳細については、man ページまたは ANSI 標準を参照してください)。
strod/strtol は最初の空白をスキップすることにも注意してください。そのため、最初の空白を含む文字列を不適切な形式として扱いたい場合は、最初の文字も確認する必要があります。
文字列をステップ実行して、文字が含まれているかどうかを確認できると思います.
。しかし、それは私の頭に浮かんだ最初のことなので、もっと確実にする他の (より良い) 方法があると確信しています。
atoi と atof は、数値以外の文字が末尾にある場合でも数値を変換します。ただし、strtol と strtod を使用すると、先頭の空白とオプションの記号がスキップされるだけでなく、数値に含まれていない最初の文字へのポインターが残ります。次に、残りが空白であることを確認できます。
それは、そもそもなぜあなたが尋ねているのかによって異なります。
数値を解析したいだけで、それが浮動小数点数か整数かがわからない場合は、浮動小数点数を解析するだけで、整数も正しく解析されます。
トリアージなどのために実際にタイプを知りたい場合は、最も関連性が高いと思われる順序でタイプをテストすることを検討する必要があります。同様に、整数を解析してみて、できない場合は浮動小数点数を解析してみてください。(逆の場合は、もう少しフロートが生成されます...)
strtoul のような新しい関数を使用したくない場合は、別の strcmp ステートメントを追加して、文字列が 0 かどうかを確認できます。
すなわち
if(atof(token) != NULL || strcmp(token, "0") == 0)