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

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


# はじまり
JSONで64ビット整数をやり取りしようと思ったら
JSON仕様では６４ビット整数が存在しない！！
Number型にすれば52ビットまでは取れるけど
それ以上は取れない
JSONではバイナリデータも転送できない

よって、それらのケースは一般的に
数字を文字列に変換し、通信をすることが多いです

もちろん、バイナリデータを base64にして送ることも可能ではありますが
その場合には エンディアンや、内部表現形式といった問題も発生するので
あまり 環境依存するものはよくありませんね

# int64_t、uint64_tから std::string　への変換
streamを使うのも簡単にできますが、ここはお手軽に
std::to_string を使いましょう

```cpp: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;
}
```


```plain:結果
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へ変換

まず

```cpp
#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系関数を使う

```cpp
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 | 何進数にするか                                                                                    |

```cpp: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系関数を使う

```c: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   | 何進数として解釈するか                                                                                        |


```cpp: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;
}
```

## 結果
```plain:結果
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
```

大丈夫ですね！