指摘により、例外について追記しました
はじまり
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
大丈夫ですね!