如何用g ++打印__int128?

时间:2014-08-04 08:33:33

标签: c++ iostream int128

我正在使用GCC内置类型__int128来处理我的C ++程序中的一些事情,没有什么真正重要的,至少不足以证明只为此使用BigInt库,但是,足以防止完全删除它。

当我遇到我的课程的打印部分时,我的问题出现了,这是一个最小的例子:

#include <iostream>

int main()
{
  __int128 t = 1234567890;

  std::cout << t << std::endl;

  return t;
}

注释掉std::cout行会使这段代码与g++很好地编译,但是这样做会导致以下错误信息:

int128.c: In function ‘int main()’:
int128.c:7:13: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘__int128’)
   std::cout << t << std::endl;
             ^
int128.c:7:13: note: candidates are:
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from int128.c:1:
/usr/include/c++/4.9/ostream:108:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
       operator<<(__ostream_type& (*__pf)(__ostream_type&))
       ^
/usr/include/c++/4.9/ostream:108:7: note:   no known conversion for argument 1 from ‘__int128’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’
/usr/include/c++/4.9/ostream:117:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>] <near match>
       operator<<(__ios_type& (*__pf)(__ios_type&))
       ^
/usr/include/c++/4.9/ostream:117:7: note:   no known conversion for argument 1 from ‘__int128’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/4.9/ostream:127:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
       operator<<(ios_base& (*__pf) (ios_base&))
       ^
/usr/include/c++/4.9/ostream:127:7: note:   no known conversion for argument 1 from ‘__int128’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/4.9/ostream:166:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long __n)
       ^
/usr/include/c++/4.9/ostream:170:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long __n)
       ^
/usr/include/c++/4.9/ostream:174:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(bool __n)
       ^
In file included from /usr/include/c++/4.9/ostream:609:0,
                 from /usr/include/c++/4.9/iostream:39,
                 from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:91:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from int128.c:1:
/usr/include/c++/4.9/ostream:181:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned short __n)
       ^
In file included from /usr/include/c++/4.9/ostream:609:0,
                 from /usr/include/c++/4.9/iostream:39,
                 from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:105:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from int128.c:1:
/usr/include/c++/4.9/ostream:192:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned int __n)
       ^
/usr/include/c++/4.9/ostream:201:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long long __n)
       ^
/usr/include/c++/4.9/ostream:205:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long long __n)
       ^
/usr/include/c++/4.9/ostream:220:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(double __f)
       ^
/usr/include/c++/4.9/ostream:224:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(float __f)
       ^
/usr/include/c++/4.9/ostream:232:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long double __f)
       ^
/usr/include/c++/4.9/ostream:245:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
       operator<<(const void* __p)
       ^
/usr/include/c++/4.9/ostream:245:7: note:   no known conversion for argument 1 from ‘__int128’ to ‘const void*’
In file included from /usr/include/c++/4.9/ostream:609:0,
                 from /usr/include/c++/4.9/iostream:39,
                 from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:119:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>] <near match>
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/4.9/bits/ostream.tcc:119:5: note:   no known conversion for argument 1 from ‘__int128’ to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from int128.c:1:
/usr/include/c++/4.9/ostream:493:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char) [with _Traits = std::char_traits<char>]
     operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
     ^
/usr/include/c++/4.9/ostream:488:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char) [with _Traits = std::char_traits<char>]
     operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
     ^
/usr/include/c++/4.9/ostream:482:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char) [with _Traits = std::char_traits<char>]
     operator<<(basic_ostream<char, _Traits>& __out, char __c)
     ^
/usr/include/c++/4.9/ostream:476:5: note: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) [with _CharT = char; _Traits = std::char_traits<char>]
     operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
     ^

是的,我知道,很多行解释__int128没有得到妥善处理......

是否有简单方式让__int128像其他任何数字类型一样打印iostream

编辑:对于那些仍然混淆C和C ++的人,是的,我读到了这个问题:how to print __uint128_t number using gcc?但是,这是针对C而不是我现在要求的C ++。

6 个答案:

答案 0 :(得分:29)

如果您不需要任何花哨的格式选项,请写作 你自己的<<运营商是微不足道的。在形式上,我怀疑 为__int128_t编写一个将被视为未定义 行为,但实际上,我认为它会起作用,直到 图书馆开始为它提供实际支持(此时, 您已退出转换运算符)。

无论如何,以下内容应该有效:

std::ostream&
operator<<( std::ostream& dest, __int128_t value )
{
    std::ostream::sentry s( dest );
    if ( s ) {
        __uint128_t tmp = value < 0 ? -value : value;
        char buffer[ 128 ];
        char* d = std::end( buffer );
        do
        {
            -- d;
            *d = "0123456789"[ tmp % 10 ];
            tmp /= 10;
        } while ( tmp != 0 );
        if ( value < 0 ) {
            -- d;
            *d = '-';
        }
        int len = std::end( buffer ) - d;
        if ( dest.rdbuf()->sputn( d, len ) != len ) {
            dest.setstate( std::ios_base::badbit );
        }
    }
    return dest;
}

请注意,这只是一个快速的临时修复,直到时间 g ++库支持该类型。它依赖于2的补充, 在__int128_t上溢出,但我会非常 如果不是这样的话会感到惊讶(正式来说,它是未定义的 行为)。如果没有,您需要修复初始化 tmp。当然,它不会处理格式的任何 选择;你可以根据需要添加。 (处理填充和 adjustfield正确地可以是非平凡的。)

答案 1 :(得分:16)

我建议不要为operator<<重载__int128_t。原因是,只要您看到某些整数类型的cout << x,您就会期望std::hexstd::setw等所有类型的操作符也能正常工作。重载运算符时最重要的指导原则是:&#34;按照内容执行操作&#34;。

作为替代方案,我建议使用decimal_string(__int128_t)函数,您可以在代码中将其用作cout << decimal_string(x);。对于字符串转换,您可以使用任何与C相关的Q&amp; As中的算法。这清楚地表明您有128位整数的特殊代码。只要标准库升级到128位支持,您就可以删除它(这些函数很容易grep)。

答案 2 :(得分:3)

股票cout无法处理__int128,但您可以使用自己的功能对其进行扩展。

对于首发,代码如下:

std::ostream& operator<<(std::ostream& os, __int128 t) {
    // TODO: Convert t to string
    return os << str;
}

在SO上有很多解决方案将128位数转换为字符串,我不会在这里重复。

关于评论中的图书馆兼容性:

如果标准库没有提供这样的处理程序,您只需要滚动自己的函数。一旦库支持该类型,您就应该在构建时看到冲突,例如[注意:内置候选运算符&lt;&lt; ],试试用int64_t。

答案 3 :(得分:0)

如果它不是性能关键,这是一种将int128转换为以10为底的字符串(当然可以随后打印)的简单易读的方法:

std::string toString(__int128 num) {
    std::string str;
    do {
        int digit = num % 10;
        str = std::to_string(digit) + str;
        num = (num - digit) / 10;
    } while (num != 0);
    return str;
}

通过将数字分成较大的块而不是一次获得一个,我们可以使此过程快几倍。但这要求我们检查每个块中是否丢失了任何前导零,并将它们重新添加到其中:

std::string toString(__int128 num) {
    auto tenPow18 = 1000000000000000000;
    std::string str;
    do {
        long long digits = num % tenPow18;
        auto digitsStr = std::to_string(digits);
        auto leading0s = (digits != num) ? std::string(18 - digitsStr.length(), '0') : "";
        str = leading0s + digitsStr + str;
        num = (num - digits) / tenPow18;
    } while (num != 0);
    return str;
}

注意:我还针对 unsigned int128s here发布了此答案的版本。

答案 4 :(得分:0)

到目前为止,答案是好的,但我只是想补充James Kanze的答案。首先请注意,由于无符号转换,因此不适用于数字-0x80000000000000000000000000000000。其次,您可以利用64位整数进行打印这一事实来优化函数实现,如下所示:

std::ostream& operator<<(std::ostream& os, __int128_t value) {
    if (value < 0) {
        os << '-';
        value = -value;
    }
    // save flags to restore them
    std::ios_base::fmtflags flags(os.flags());
    // set zero fill
    os << std::setfill('0') << std::setw(13);

    // 128-bit number has at most 39 digits,
    // so the below loop will run at most 3 times
    const int64_t modulus = 10000000000000; // 10**13
    do {
        int64_t val = value % modulus;
        value /= modulus;
        if (value == 0) {
            os.flags(flags);
            return os << val;
        }
        os << val;
    } while (1);
}

答案 5 :(得分:0)

看似简单的方法

std::ostream& operator<<(std::ostream& os, __int128 x){
    if(x<0) return os << "-" << -x;
    if(x<10) return  os << (char)(x+'0');
    return os << x/10 << (char)(x%10+'0');
}

请参阅我的其他评论,以尝试实现性能更高的尝试失败。