c++ iostream int128

c++ - Cómo imprimir__int128 en g++?



iostream (4)

Aunque esta es una pregunta tan antigua, este es el resultado principal cuando busqué cómo imprimir __int128 en la pantalla usando C ++. Recientemente tuve que hacer esto y encontré la respuesta de James Kanze la más adecuada para mi aplicación y la más fácil de entender. Esto es solo una versión simplificada y simplificada:

using Integer128 = __int128; std::ostream& operator<<(std::ostream& dest, const Integer128& value) { Integer128 tmp = value < 0 ? -value : value; std::array<char, 128> buffer; auto d = buffer.begin(); while(tmp != 0){ *d++ = "0123456789"[tmp % 10]; tmp /= 10; } if(value < 0){ *d++ = ''-''; } std::ostream_iterator<char> out_it(dest); std::reverse_copy(buffer.begin(), d, out_it); return dest; }

Estoy usando el tipo __int128 de __int128 para algunas cosas en mi programa C ++, nada realmente significativo, al menos no lo suficiente como para justificar el uso de la biblioteca BigInt solo para eso y, sin embargo, lo suficiente como para evitar que se elimine por completo.

Mi problema viene cuando me encuentro con las partes de impresión de mis clases, aquí hay un ejemplo mínimo:

#include <iostream> int main() { __int128 t = 1234567890; std::cout << t << std::endl; return t; }

Al comentar la línea std::cout hará que este código se compile muy bien con g++ , pero tenerlo provocará el siguiente mensaje de error:

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) ^

Sí, lo sé, muchas líneas para explicar que __int128 simplemente no se maneja correctamente ...

¿Existe alguna manera simple de que __int128 sea ​​impreso por iostream como cualquier otro tipo numérico?

EDITAR: Para aquellos que aún confunden C y C ++, sí, leí la pregunta: ¿cómo imprimir el número __uint128_t usando gcc? Pero esto fue para C y no para C ++, como estoy preguntando ahora.


La __int128 stock no maneja __int128 , pero puede __int128 con su propia función.

Para empezar, codifica algo como esto:

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

Hay muchas soluciones en SO para convertir un número de 128 bits en una cadena, no repetiré aquí.

Acerca de la compatibilidad de la biblioteca en el comentario:

Solo necesita desplegar su propia función si la biblioteca estándar no proporciona dicho controlador. Una vez que la biblioteca admite el tipo, debería ver un conflicto al compilar, algo así como [nota: operador de candidato incorporado <<], vaya a intentarlo con int64_t.


Recomendaría no sobrecargar al operator<< por __int128_t . La razón es que cada vez que vea cout << x para un tipo entero, esperaría que todo tipo de manipuladores como std::hex o std::setw también funcionen. La guía más importante cuando se sobrecarga a los operadores es: "haz lo que hacen los ints".

Como alternativa, recomendaría usar una función decimal_string(__int128_t) que puede usar como cout << decimal_string(x); en tu código Para la conversión de cadenas, puede usar el algoritmo de cualquiera de las preguntas y respuestas relacionadas con C. Esto deja en claro que tienes un código especial para tus entradas de 128 bits. Siempre que la biblioteca estándar se actualice a la compatibilidad de 128 bits, puede soltarla (y es fácil grep para estas funciones).


Si no necesita ninguna de las opciones de formateo sofisticadas, escribir su propio << operador es trivial. Formalmente, sospecho que escribir uno para __int128_t se consideraría un comportamiento indefinido, pero en la práctica, creo que funcionaría, hasta que la biblioteca comience a brindarle soporte real (en ese momento, retiraría su operador de conversión).

De todos modos, algo como lo siguiente debería funcionar:

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; }

Tenga en cuenta que esto es solo una solución rápida y temporal, hasta que la biblioteca g ++ admita el tipo. Cuenta con el complemento de 2, __int128_t en desbordamiento, para __int128_t , pero me sorprendería mucho que ese no fuera el caso (formalmente, es un comportamiento indefinido). De lo contrario, deberá reparar la inicialización de tmp . Y, por supuesto, no maneja ninguna de las opciones de formato; puedes agregarlo como quieras (Manejar el relleno y el campo de adjustfield correctamente puede ser no trivial.)