web-dev-qa-db-ja.com

Cでのcharからintへの変換

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

char c = '5';

そして、c5の代わりに'5'を保持させたいのですが、このように100%移植可能ですか?

c = c - '0';

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

35
Ori Popowski

はい、これは安全な変換です。 Cは動作することを要求します。この保証は、最新のISO C標準のセクション5.2.1段落2にあり、その最近のドラフトは N157

基本ソースと基本実行の両方の文字セットには、次のメンバーが必要です。
[...]
10進数
_0 1 2 3 4 5 6 7 8 9_
[...]
ソースと実行の基本文字セットの両方で、上記の10進数字リストの0の後の各文字の値は、前の値よりも1大きくなければなりません。

ASCIIとEBCDIC、およびそれらから派生した文字セットは、この要件を満たしているため、C標準はそれを課すことができました。文字はであることに注意してください。 not連続したiN 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'を減算する最初のアプローチは、これを行う適切な方法です。ここでは、文字列としての数値を「真の」数値に変換する推奨される標準的なアプローチがどのように使用されるかを示したいだけです。

27
unwind

これを試して :

char c = '5' - '0';
9
lsalamon
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進文字を整数に変換します。

5
spinfire

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

5
weloytty

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

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

2
zooropa

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

1
Joe Corkery

他の人が示唆しているように、しかし関数に包まれています:

int char_to_digit(char c) {
    return c - '0';
}

次に、関数を使用します。将来、別の方法を使用することにした場合、実装(パフォーマンス、文字セットの違いなど)を変更するだけでよく、呼び出し元を変更する必要はありません。

このバージョンでは、cに数字を表す文字が含まれていると想定しています。 ctype.hのisdigit関数を使用して、関数を呼び出す前にそれを確認できます。

0
MyNameIsZero

単にtheatol() functionを使用できます:

#include <stdio.h>
#include <stdlib.h>

int main() 
{
    const char *c = "5";
    int d = atol(c);
    printf("%d\n", d);

}
0
Dylan halls

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

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

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

// 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
}

追伸私はこれがオーバーキルであることを知っています。すぐには明らかにならないかもしれない代替ソリューションとして提示したかっただけです。

0
Ates Goral

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

0
chinmay