Edited at

【C++11】64ビット整数と文字列の相互変換

More than 3 years have passed since last update.

指摘により、例外について追記しました


はじまり

JSONで64ビット整数をやり取りしようと思ったら

JSON仕様では64ビット整数が存在しない!!

Number型にすれば52ビットまでは取れるけど

それ以上は取れない

JSONではバイナリデータも転送できない

よって、それらのケースは一般的に

数字を文字列に変換し、通信をすることが多いです

もちろん、バイナリデータを base64にして送ることも可能ではありますが

その場合には エンディアンや、内部表現形式といった問題も発生するので

あまり 環境依存するものはよくありませんね


int64_t、uint64_tから std::string への変換

streamを使うのも簡単にできますが、ここはお手軽に

std::to_string を使いましょう


to_string

#include <limits>

#include <iostream>
#include <string>
#include <cstdint>
template<typename T> using lim = std::numeric_limits<T>;
int main(){
using namespace std;
cout
<< "std::numeric_limits<int64_t>::max()" << endl
<< lim<int64_t>::min() << endl
<< to_string(lim<int64_t>::min()) << endl;
cout
<< "std::numeric_limits<int64_t>::max()" << endl
<< lim<int64_t>::max() << endl
<< to_string(lim<int64_t>::max()) << endl;
cout
<< "std::numeric_limits<uint64_t>::max()" << endl
<< lim<uint64_t>::min() << endl
<< to_string(lim<uint64_t>::min()) << endl;
cout
<< "std::numeric_limits<uint64_t>::max()" << endl
<< lim<uint64_t>::max() << endl
<< to_string(lim<uint64_t>::max()) << endl;

return 0;
}



結果

std::numeric_limits<int64_t>::max()

-9223372036854775808
-9223372036854775808
std::numeric_limits<int64_t>::max()
9223372036854775807
9223372036854775807
std::numeric_limits<uint64_t>::max()
0
0
std::numeric_limits<uint64_t>::max()
18446744073709551615
18446744073709551615

大丈夫ですね!


std::stringから int64_t、uint64_tへ変換

まず

#include <type_traits>

#include <cstdint>
static_assert(std::is_same<long long, std::int64_t>::value, "err");
static_assert(std::is_same<unsigned long long, std::uint64_t>::value, "err");

がエラーにならないと仮定しないといけません。注意しましょう。

エラー処理を例外で行うケースは

signedの場合はstd::stoll、unsignedはstd::stoull

エラー処理をerrnoで行うケースは

signedの場合はstd::strtoll、unsignedはstd::strtoull

を使います


stoi系関数を使う

namespace std {

long long stoll(const string& str, size_t* idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t* idx = 0, int base = 10);
long long stoll(const wstring& str, size_t* idx = 0, int base = 10);
unsigned long long stoull(const wstring& str, size_t* idx = 0, int base = 10);
}

引数
説明

str
変換したい文字列

idx
変換できなかった最初の文字の要素番号を書き込む変数へのポインター。nullptrを指定すれば無視される。

base
何進数にするか


stoi系関数を使う

#include <limits>

#include <iostream>
#include <string>
template<typename T> using lim = std::numeric_limits<T>;
int main(){
using namespace std;
using ll = long long;
using ull = unsigned long long;

cout
<< "std::numeric_limits<long long>::max()" << endl
<< lim<ll>::min() << endl
<< stoll(to_string(lim<ll>::min())) << endl;
cout
<< "std::numeric_limits<long long>::max()" << endl
<< lim<ll>::max() << endl
<< stoll(to_string(lim<ll>::max())) << endl;
cout
<< "std::numeric_limits<unsigned long long>::max()" << endl
<< lim<ull>::min() << endl
<< stoull(to_string(lim<ull>::min())) << endl;
cout
<< "std::numeric_limits<unsigned long long>::max()" << endl
<< lim<ull>::max() << endl
<< stoull(to_string(lim<ull>::max())) << endl;

return 0;
}



strtol系関数を使う


C99/11

long long int strtoll(const char * restrict nptr, char ** restrict endptr, int base);

unsigned long long int strtoull(const char * restrict nptr, char ** restrict endptr, int base);

引数
説明

nptr
変換したい文字列

endptr
変換できなかった最初の文字へのポインターを書き込む変数へのポインター。nullptrを指定すれば無視される。

base
何進数として解釈するか


strtol系関数を使う場合

#include <cstdlib>

#include <limits>
#include <iostream>
#include <string>
#include <cerrno>
template<typename T> using lim = std::numeric_limits<T>;
int main(){
using namespace std;
using ll = long long;
using ull = unsigned long long;

cout << "std::numeric_limits<long long>::max()" << endl;
cout << lim<ll>::min() << endl;
{
const auto s = to_string(lim<ll>::min());
errno = 0;
char* endptr;
const auto re = strtoll(s.c_str(), &endptr, 10);
if(0 != errno || (0 == re && endptr == s.c_str())) return -1;//error
cout << re << endl;
}

cout << "std::numeric_limits<long long>::max()" << endl;
cout << lim<ll>::max() << endl;
{
const auto s = to_string(lim<ll>::max());
errno = 0;
char* endptr;
const auto re = strtoll(s.c_str(), &endptr, 10);
if(0 != errno || (0 == re && endptr == s.c_str())) return -1;//error
cout << re << endl;
}

cout << "std::numeric_limits<unsigned long long>::max()" << endl;
cout << lim<ull>::min() << endl;
{
const auto s = to_string(lim<ull>::min());
errno = 0;
char* endptr;
const auto re = strtoull(s.c_str(), &endptr, 10);
if(0 != errno || (0 == re && endptr == s.c_str())) return -1;//error
cout << re << endl;
}

cout << "std::numeric_limits<unsigned long long>::max()" << endl;
cout << lim<ull>::max() << endl;
{
const auto s = to_string(lim<ull>::max());
errno = 0;
char* endptr;
const auto re = strtoull(s.c_str(), &endptr, 10);
if(0 != errno || (0 == re && endptr == s.c_str())) return -1;//error
cout << re << endl;
}

return 0;
}



結果


結果

std::numeric_limits<long long>::max()

-9223372036854775808
-9223372036854775808
std::numeric_limits<long long>::max()
9223372036854775807
9223372036854775807
std::numeric_limits<unsigned long long>::max()
0
0
std::numeric_limits<unsigned long long>::max()
18446744073709551615
18446744073709551615

大丈夫ですね!