37

たとえば、単一の数値をその数値に変換するchar場合:

char c = '5';

の代わりにc保持したいのですが、このようにして100%移植できますか?5'5'

c = c - '0';

すべての文字セットは数字を連続した順序で格納していると聞いたので、おそらくそうだと思いますが、この変換を行うための組織化されたライブラリ関数があるかどうか、および従来はどのように行われているかを知りたいです。私は本当の初心者です:)

4

10 に答える 10

28

はい、これは安全な変換です。C では、それが機能する必要があります。この保証は、最新の ISO C 標準のセクション 5.2.1 パラグラフ 2 にあり、その最近のドラフトはN1570です。

基本的なソース文字セットと基本的 な実行文字セットの両方には、次のメンバーが含ま れます
。10 進数の桁数は、前の値よりも 1 大きくなります。

0 1 2 3 4 5 6 7 8 9

ASCII と EBCDIC の両方、およびそれらから派生した文字セットは、この要件を満たしています。これが、C 標準がそれを課すことができた理由です。文字はEBCDIC では連続していないことに注意してください。C では連続している必要はありません。

単一の に対してそれを行うライブラリ関数はありませんchar。最初に文字列を作成する必要があります。

int digit_to_int(char d)
{
 char str[2];

 str[0] = d;
 str[1] = '\0';
 return (int) strtol(str, NULL, 10);
}

atoi()文字列を取得したら、関数を使用して変換を行うこともできますが、strtol()より安全で安全です。

ただし、コメント者が指摘しているように、この変換を行うために関数を呼び出すのは非常にやり過ぎです。「0」を減算する最初のアプローチは、これを行う適切な方法です。ここでは、数値を文字列として「真の」数値に変換するという推奨される標準的なアプローチがどのように使用されるかを示したかっただけです。

于 2009-04-23T13:30:24.503 に答える
9

これを試して :

char c = '5' - '0';
于 2009-04-23T13:30:13.363 に答える
5
int i = c - '0';

これは文字に対して検証を実行しないことに注意する必要があります。たとえば、文字が「a」の場合、91-48 = 49になります。特に、ユーザーまたはネットワーク入力を処理している場合は、おそらくプログラムの不正な動作を回避するために検証を実行します。範囲を確認してください。

if ('0' <= c &&  c <= '9') {
    i = c - '0';
} else {
    /* handle error */
}

変換で16進数を処理する場合は、範囲を確認して適切な計算を実行できることに注意してください。

if ('0' <= c && c <= '9') {
    i = c - '0';
} else if ('a' <= c && c <= 'f') {
    i = 10 + c - 'a';
} else if ('A' <= c && c <= 'F') {
    i = 10 + c - 'A';
} else {
    /* handle error */
}

これにより、大文字または小文字に依存しない単一の16進文字が整数に変換されます。

于 2009-04-24T14:12:02.777 に答える
5

atoi標準ライブラリの一部である を使用できます。

于 2009-04-23T13:29:40.153 に答える
3

変換するのは 1 文字だけなので、関数 atoi() はやり過ぎです。atoi() は、数値の文字列表現を変換する場合に便利です。他の投稿では、この例を示しています。あなたの投稿を正しく読んだ場合、変換しているのは数字 1 文字だけです。したがって、0 から 9 の範囲の文字のみを変換します。1 つの数字のみを変換する場合は、'0' を減算するという提案により、必要な結果が得られます。これが機能する理由は、ASCII値が連続しているためです(あなたが言ったように)。したがって、ASCII 値 0 を減算すると (ASCII 値 48 - ASCII テーブルを参照)値の場合) 数字の文字から数値の値が得られます。したがって、c = c - '0' の例で、c = '5' の場合、実際に起こっているのは 53 (5 の ASCII 値) - 48 (0 の ASCII 値) = 5 です。

この回答を最初に投稿したとき、異なる文字セット間で 100% 移植可能であるというあなたのコメントを考慮していませんでした。私はさらに周りを見回しましたが、あなたの答えはまだほとんど正しいようです。問題は、8 ビット データ型である char を使用していることです。これは、すべての文字タイプで機能するとは限りません。Joel Spolsky による Unicodeに関する記事を読むUnicode の詳細については、こちらをご覧ください。この記事では、文字には wchar_t を使用すると述べています。これは彼にとってうまくいき、彼は自分の Web サイトを 29 の言語で公開しています。したがって、char を wchar_t に変更する必要があります。それ以外は、値127以下の文字は基本的に同じだという。これには、数字を表す文字が含まれます。これは、あなたが提案した基本的な数学が、あなたが達成しようとしていたものに対して機能するはずであることを意味します.

于 2009-04-23T13:50:33.957 に答える
1

はい。この例のように、標準の ASCII 文字を使用している限り、これは安全です。

于 2009-04-23T13:28:27.923 に答える
0

'0'、'1'、'2'.... の ASCII コードは 48 から 57 に配置されるため、それらは本質的に連続しています。算術演算では、char データ型を int データ型に変換する必要があります。したがって、基本的に行っていることは次のとおりです。53-48 したがって、整数演算を実行できる値 5 が格納されます。コンパイラはエラーを出さず、モジュロ 256 演算を実行して値を許容範囲内に収めます。

于 2014-06-21T15:46:44.120 に答える
0

通常、入力が「0」から「9」の範囲にあるという保証がない場合は、次のようなチェックを実行する必要があります。

if (c >= '0' && c <= '9') {
    int v = c - '0';
    // safely use v
}

別の方法は、ルックアップ テーブルを使用することです。より少ない (おそらくより高速な) コードで、単純な範囲チェックと変換が得られます。

// one-time setup of an array of 256 integers;
// all slots set to -1 except for ones corresponding
// to the numeric characters
static const int CHAR_TO_NUMBER[] = {
    -1, -1, -1, ...,
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // '0'..'9'
    -1, -1, -1, ...
};

// Now, all you need is:

int v = CHAR_TO_NUMBER[c];

if (v != -1) {
    // safely use v
}

PS私はこれがやり過ぎであることを知っています。すぐには明らかにならない可能性のある代替ソリューションとして提示したかっただけです。

于 2009-04-24T15:33:23.687 に答える