char型をint型に変換する方法と注意【数値化 キャスト 文字列変換】


単純なキャスト方法だけでなく、数字を数値に変換するテクニックや文字列をint型やdouble型の数値に変換する方法も紹介します。

目次

スポンサーリンク

数字から数値に変換する

文字型の数字を数値に変換する方法です。単純なキャストではなく、char型の数字'9'をint型の整数値9に変換します。今回紹介するテクニックはJavaやPHP等の言語でも活用することが出来ます。

char c = '1';
int i = c - '0';
printf("%d", i); // 1

このように数字 - '0'という記述を用います。

これは文字型の内部表現が整数値であることを活用したテクニックです。実際に'1'という文字は49という整数値で表現されています。文字'0'の場合は48です。

printf("%d", (int)'1'); // 49
printf("%d", (int)'0'); // 48

ですから、'1''0'の文字同士を引き算した場合には、内部表現4948同士の引き算が行われることになり、結果として1という値が導き出されます。

printf("%d", '1' - '0'); // 1

また文字'2'の内部表現は50ですから、'2' - '0'の結果は当然2(50 – 48)になります。

printf("%d", '2' - '0'); // 2

ASCIIコードやUTF-8等、多くの文字コードでは、文字09は連番で定義されているため、数字 - '0'という式は多くの場面で汎用的に使えます。

参考までに、文字09までのASCIIコード表を示しておきます。

文字10進数16進数
‘0’480x30
‘1’490x31
‘2’500x32
‘3’510x33
‘4’520x34
‘5’530x35
‘6’540x36
‘7’550x37
‘8’560x38
‘9’570x39

これらのように数字文字の連番が保証されている環境であれば、以下のような数字判定処理を書くことも出来ます。

bool isDigit(char c) {
   return c >= '0' && c <= '9';
}
isDigit('8'); // true
isDigit('a'); // false

単純なキャスト

char型をint型にキャストする場合はunsigned char型にキャストする必要があります。

char c = 'a';
int i = (unsigned char)c;
printf("%d", i); // 97

符号付きのchar型は符号拡張によって予期せぬ変換が行われる場合があるため注意してください。

char c = (char)255;
printf("%d", c);                //  -1
printf("%d", (int)c);           //  -1
printf("%d", (unsigned char)c); // 255

char型の255は2進数で0b11111111という表現がされていますが、これをint型に変換すると0b11111111111111111111111111111111と符号拡張されてしまい結果、値は-1となってしまうのです。

逆にunsigned char型を経由した変換であれば、符号拡張が起こらないため、int型への暗黙キャスト時には0b00000000000000000000000011111111という変換が行われ、値255を維持することが出来ます。

特にC言語の標準関数では、255-1 (EOF)を区別する可能性があるため注意が必要です。文字をint型として受け取る標準関数(isalpha, putchar, 等々)を利用する際には明示的にキャストを行うようにすると安心です。

int main(int argc, const char *argv[]) {
  // この場合は128 ~ 255の値が渡ってくる可能性を考慮する
  return isdigit((unsigned char)argv[0][0]); 
  // この程度なら不要
  return isdigit('c');
}

符号拡張と整数拡張によって引き起こされる先程の問題については、コンパイラ側が事前に警告を行ってくれる場合もあります。

char c = 0xff;
// 警告:Comparison of constant 255 with expression of type 'char' is always false
puts(c == 0xff ? "y" : "n"); // "n"

以下のようなケースでは警告が発生しないため注意が必要です。

void test(int c) {
  puts(c == 0xE3 ? "y" : "n");
}

int main() {
  char s[] = "あ"; // {0xE3, 0x81, 0x82, '\0'}
  test((unsigned char)s[0]); // "y"
  test(s[0]);                // "n"
}

なおsigned charと言う形で符号付きのchar型であることが明示されているようなケースでは、そのままint型へキャストしたほうが正しい判断と言えます。

signed char c = -2;
int i = (int)c; // 明示的な型キャスト
int j = c;      // 暗黙のキャスト

文字列から数値に変換する

文字列型からint型やdouble型の数値に変換する場合にはatoi関数やatof関数を用います

int    i = atoi("9");
double f = atof("3.1");
long   l = atol("-1");

printf("%d, %f, %ld", i, f, l); // 9, 3.100000, -1
printf("%f", atof("1e3"));      // 1000.000000

変換が失敗した場合には値0が返されます。

printf("%lld", atoll("a")); // 0

広告