[ C++で開発 ]

文字列と数値間の変換

実現方法

文字列で表現された数値を、組み込み型のintなどのインスタンスに変換したり、逆にint型などのインスタンスを文字列に変換したりとした処理をC++で記述するのは意外と面倒です。使用するライブラリによって書き方がいくつかあります。

  1. C言語標準関数strtol系およびsnprintfを使用する方法*1
  2. C++言語標準関数 sstreamを使用する方法
  3. Boostライブラリのlexical_castを使用する方法

型安全性(実行時エラーよりコンパイルエラー)、テンプレートによるラッピング、バッファ管理のラッピング、記述の簡潔さを考慮すると、3.の方法がもっとも扱いやすいのですが、基数(16進数等)を指定することができないという制約があります。

注記*1
C言語のatoi系マクロ、sscanf関数は原則使用しない。エラー耐性がなく品質確保が難しいためである。

実装 1:strtol系

まず、文字列から整数に変換するために使用するstrtol系の関数は以下となります。

JIS X 3010 プログラム言語C 7.20.1.4より抜粋

#include <stdlib.h>
関数名 概要 シグニチャ
strtol nptrが指す文字列の最初の部分をlong int型に変換する
long int strtol(
    const char * restrict nptr,
    char ** restrict endptr,
    int base);             
strtoll nptrが指す文字列の最初の部分をlong long int型に変換する
long long int strtoll(
    const char * restrict nptr,
    char ** restrict endptr,
    int base);
strtoul nptrが指す文字列の最初の部分をunsigned long int型に変換する
unsigned long int strtol(
    const char * restrict nptr,
    char ** restrict endptr,
    int base); 
strtoull nptrが指す文字列の最初の部分をunsigned long long int型に変換する
unsigned long long int strtol(
    const char * restrict nptr,
    char ** restrict endptr,
    int base); 

整数を文字列に変換するsnprintf関数は以下となります。

JIS X 3010 プログラム言語C 7.19.6.5より抜粋

#include <stdio.h>
関数名 概要 シグニチャ
snprintf formatの書式にもとづき変換した出力をsの指す配列へ書き込む。n-1番目より後の出力文字は捨てられる。
int snprintf(
    char * restrict s,
    size_t n,
    const char * restrict format, ...);

実装 2:stringstreamによる方法

ここでは、文字列から数値へ変換する関数、数値から文字列へ変換する関数のインタフェースをC++流に定義し、上記の各実装方法で実装します。

namespace stringutil {
template<typename T>
T string2binary(const std::string& text, int base);

template<typename T>
std::string binary2string(T value, int base);
}

Tには、数値型のいずれかが合致します。

まず、2.の方法で基数を含めた変換を実現する方法を実装してみます。

stringstream

iostreamの入出力先を文字列に変換可能なistringstream/ostringstreamとしたものです。

文字列から数値への変換

StringUtil.h
#include <sstream>
#include <string>
#include <cassert>

namespace stringutil {

template<typename T>
T string2binary(const std::string& text, int base) {
    assert(base == 8 || base == 10 || base == 16);
    std::istringstream is(text);
    T value;
    switch (base) {
    case 8:
        is >> std::oct >> value;
        break;
    case 10:
        is >> value;
        break;
    case 16:
        is >> std::hex >> value;
        break;
    default:
        ;
    }

    return value;
}    

}

数値から文字列への変換

StringUtil.h
#include <sstream>
#include <string>
#include <cassert>

namespace stringutil {

template<typename T>
std::string binary2string(T value, int base) {
    assert(base == 8 || base == 10 || base == 16);
    std::ostringstream os;
    switch (base) {
    case 8:
        if (value < 0) {
            os << '-';
            value *= -1;
        }
        os << std::oct;
        break;
    case 10:
        os << std::dec;
        break;
    case 16:
        if (value < 0) {
            os << '-';
            value *= -1;
        }
        os << std::hex;
        break;
    }
    os << value;  
    return os.str();
}

}

実装 3:Boostライブラリのlexical_castを使用する方法

次に、3.の方法で基数を含めた変換を実現する方法を実装してみます。