文字列から数値への変換

呼称: 文字列から数値への変換
目的: 文字列を数値へ変換する
特徴: strtol()/strtoul() を使用するとエラーを検出できる
用例: どこでも、いつでも
備考: errno を検査する必要がある*1

C 言語で文字列から数値への変換はよく使う処理です。数値として計算する必要はなくても、数値にしておくことで関数への値渡しが可能であったり、桁数を考慮する必要がなかったり、何かを便利なことがあります。シンプルな処理なので標準関数を呼び出せばそれで良いと考えがちですが、きちんとエラーを検出しようとすると考慮が必要です。

例えば、以下のようなケースにエラーを検出するかどうかがあります。

  • 数値ではない文字列が指定されている
  • 数値と数値ではない文字列が混在している
  • 扱う数値型の範囲を超えた文字列が指定されている


man を調べると atoi() は*2

strtol(nptr, (char **) NULL, 10);

と同じとあります。atoi() ではエラーを検出できないことに注意する必要があります。

#include <stdio.h>
#define __USE_ISOC99
#include <limits.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>

#define BASE_NUM    10

void
usage()
{
    printf("./str2num 538528\n");
}

int
main(int argc, char *argv[])
{
    int                 i;
    unsigned int        ui;
    char                *num_str, *endptr;

    if (argc < 2) {
        usage();
        return EXIT_SUCCESS;
    }
    num_str = argv[1];

    printf("int max        : %d\n", INT_MAX);
    printf("uint max       : %u\n", UINT_MAX);
    printf("---------------------------\n");

    i = atoi(num_str);
    printf("use atoi()     : %d\n", i);

    errno = 0;
    i = strtol(num_str, &endptr, BASE_NUM);
    if (*endptr != '\0' || (i == INT_MAX && errno == ERANGE)) {
        fprintf(stderr, "strtol() error : %s\n", num_str);
    } else { 
        printf("use strtol()   : %d\n", i);
    }

    errno = 0;
    ui = strtoul(num_str, &endptr, BASE_NUM);
    if (*endptr != '\0' || (ui == UINT_MAX && errno == ERANGE)) {
        fprintf(stderr, "strtoul() error: %s\n", num_str);
    } else { 
        printf("use strtoul()  : %u\n", ui);
    }

    return EXIT_SUCCESS;
}

実行結果。

$ gcc -Wall str2num.c -o str2num
$ ./str2num 123
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 123
use strtol()   : 123
use strtoul()  : 123

$ ./str2num 123abc
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 123
strtol() error : 123abc
strtoul() error: 123abc

$ ./str2num ""
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 0
use strtol()   : 0
use strtoul()  : 0

$ ./str2num a
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 0
strtol() error : a
strtoul() error: a

$ ./str2num 2147483647
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 2147483647
use strtol()   : 2147483647
use strtoul()  : 2147483647

$ ./str2num 2147483648
int max        : 2147483647
uint max       : 4294967295
---------------------------
use atoi()     : 2147483647
strtol() error : 2147483648
use strtoul()  : 2147483648