Dado este C++11 programa, debo esperar para ver un número o una letra? O no hacer con las expectativas?

#include <cstdint>
#include <iostream>

int main()
{
    int8_t i = 65;
    std::cout << i;
}

Hace el estándar especifica si este tipo puede ser o será un tipo de carácter?

  • int según specifcations debe al menos 16 bits
  • uint8_t es de tipo entero, no un tipo de carácter. Espero números, no letras. Parece otro comité de C++ faux pas (GCC 6.3.1-1 imprime como caracteres). El comité consiguió parcialmente correctas con std::byte. std::byte no se imprime como un tipo de carácter (por el momento, no se imprime en todo. Esperemos que se corrija en el futuro).
InformationsquelleAutor Drew Dormann | 2013-04-09

5 Comentarios

  1. 25

    De § 18.4.1 [cstdint.syn] de C++0x FDI (N3290), int8_t es opcional typedef que se especifica como sigue:

    namespace std {
      typedef signed integer type int8_t;  //optional
      //...
    } //namespace std

    § 3.9.1 [basic.fundamentales] estados:

    Hay cinco estándar firmado tipos enteros: «signed char«, «short int«, «int«, «long int«, y «long long int«. En esta lista, cada tipo ofrece, al menos, tanto de almacenamiento como de aquellos que lo precede en la lista. También puede ser definida por implementación extendido entero con signo de tipos. El estándar y extendido entero con signo de tipos son llamados colectivamente entero con signo de tipos.

    Tipos bool, char, char16_t, char32_t, wchar_t, y el signed y unsigned integer tipos son llamados colectivamente integral tipos. Un sinónimo de tipo integral, es de tipo entero.

    § 3.9.1 también estados:

    En particular, la aplicación de una llanura char objeto puede tomar los mismos valores como signed char o un unsigned char; que uno es de aplicación definido.

    Es tentador concluir que int8_t puede ser un typedef de char siempre char artículos firmados valores; sin embargo, este no es el caso como char no está entre la lista de entero con signo de tipos (estándar y posiblemente extendido entero con signo de tipos). Véase también Stephan T. Lavavej comentarios en std::make_unsigned y std::make_signed.

    Por lo tanto, ya sea int8_t es un typedef de signed char o es un largo entero con signo tipo de cuyos objetos ocupan exactamente 8 bits de almacenamiento.

    Para responder a su pregunta, sin embargo, usted no debe hacer suposiciones. Dado que las funciones de ambas formas x.operator<<(y) y operator<<(x,y) se han definido, § 13.5.3 [al dorso.binario] dice: a los que nos referimos § 13.3.1.2 [al dorso.partido.oper] para determinar la interpretación de std::cout << i. § 13.3.1.2 a su vez dice que la aplicación se selecciona a partir del conjunto de candidatos para las funciones de acuerdo con el § 13.3.2 y § 13.3.3. A continuación, busque el § 13.3.3.2 [al dorso.ics.rango] para determinar que:

    • La template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char) plantilla podría ser llamado si int8_t es una Coincidencia Exacta para signed char (es decir, un typedef de signed char).
    • De lo contrario, el int8_t sería promovido a int y la basic_ostream<charT,traits>& operator<<(int n) función miembro sería llamado.

    En el caso de std::cout << u para u un uint8_t objeto:

    • La template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char) plantilla podría ser llamado si uint8_t es una Coincidencia Exacta para unsigned char.
    • Lo contrario, ya que int puede representar a todos uint8_t valores, la uint8_t sería promovido a int y la basic_ostream<charT,traits>& operator<<(int n) función miembro sería llamado.

    Si siempre desea imprimir un carácter, el más seguro y claro de la opción es:

    std::cout << static_cast<signed char>(i);

    Y si siempre desea imprimir un número:

    std::cout << static_cast<int>(i);
    • «la Norma permite typedef char int8_t«: yo creo que, esto no es cierto porque char es de tipo entero, pero no es un entero con signo tipo, incluso si tiene un signo. Ver mi post para un (esperemos correcta) la explicación en este (algo confusa) terminología.
    • El Estándar de C++ no se puede incluir char en la lista de firmado los tipos integer o entero sin signo tipos de debido a que la Norma permite char objetos a tomar con o sin signo de los valores. Así que, no estoy de acuerdo con tu punto de vista que sólo porque char no aparece en la lista de firmado los tipos integer, esto significa que un char no es un firmado tipo integer aún si se toma en valores con signo debido a que el Estándar de no incluir char en la lista de firmado los tipos integer o entero sin signo tipos de.
    • Aunque su razonamiento tiene sentido para mí, yo creo en lo que me dijo. Al parecer, Esteban T. Lavavej de acuerdo conmigo: «, Mientras que «char» es obligatorio tener el mismo signedness y el rango como «signed char» o «unsigned char» (cual es definida por implementación), «char» no es un entero con signo tipo de ni un tipo de entero sin signo». Véase también Johannes Schaub – litb‘s comentario aquí
    • Ahora creo que estás en lo correcto. Gracias por encontrar esos dos argumentos. Puesto que todo lo que Stephan T. Lavavej escribió hace sentido para mí, yo creo que std::make_signed<int8_t>::type tendría que ser de forma idéntica int8_t porque int8_t se especifica como un firmado tipo integer. Por lo tanto, int8_t no puede ser un typedef de char incluso si char objetos de tomar en valores con signo.
  2. 23

    int8_t es exactamente 8 bits de ancho (si es que existe).

    La única predefinidos tipos enteros que pueden ser de 8 bits son char, unsigned char, y signed char. Ambos short y unsigned short están obligados a tener al menos 16 bits.

    Así int8_t debe ser un typedef para signed char o llanura char (el último, si llanura char es firmado).

    Si desea imprimir un int8_t valor como un entero en lugar de como un personaje, que puede convertir explícitamente a int.

    En principio, un compilador de C++ podría definir un 8-bit extendido de tipo entero (tal vez se llama algo así como __int8), y hacer int8_t un typedef para ello. La única razón que se me ocurre de hacerlo sería para evitar la toma de int8_t un tipo de carácter. No sé de cualquiera de los compiladores de C++ que han hecho esto.

    Tanto int8_t y ampliado los tipos enteros fueron introducidos en C99. Para C, no hay ninguna razón particular para definir un 8-bit extendido de tipo entero cuando el char tipos están disponibles.

    ACTUALIZACIÓN:

    No estoy del todo cómodo con esta conclusión. int8_t y uint8_t se introdujeron en C99. En C, no es particularmente importante si son los tipos de caracteres o no; no hay operaciones para las que la distinción que hace una diferencia real. (Incluso putc(), el nivel más bajo de caracteres de salida de la rutina en el estándar de C, toma el carácter para ser impreso como un int argumento). int8_t, y uint8_t, si están definidos, es casi seguro que se definen como los tipos de caracteres — pero los tipos de caracteres son más que una pequeña tipos enteros.

    C++ proporciona específicos versiones sobrecargadas de operator<< para char, signed char, y unsigned char, por lo que std::cout << 'A' y std::cout << 65 producir muy diferentes de salida. Más tarde, C++ adoptado int8_t y uint8_t, pero de tal manera que, como en C, son casi ciertamente los tipos de caracteres. Para la mayoría de las operaciones, esto no importa más de lo que se hace en C, pero para std::cout << ... hace una diferencia, ya que esta:

    uint8_t x = 65;
    std::cout << x;

    probablemente imprimir la carta A más que el número de 65.

    Si quieres un comportamiento coherente, agregar un cast:

    uint8_t x = 65;
    std::cout << int(x); //or static_cast<int>(x) if you prefer

    Creo que la raíz del problema es que hay algo que falta en el lenguaje: muy estrecho tipos enteros que no son los tipos de caracteres.

    Como para el intención, yo podría especular que los miembros del comité no se piense sobre el tema, o decidió que no valía la pena abordar. Uno podría argumentar (y me gustaría) que los beneficios de la adición de la [u]int*_t tipos a la norma supera el inconveniente de su extraño comportamiento con std::cout << ....

    • Traté de encontrar una referencia para un tamaño mínimo de short (aparte de por lo menos el tamaño de signed char) y no lo pude encontrar – podría proporcionar una referencia?
    • El estándar de C++ 3.9.1: «El signed y unsigned integer tipos deberá satisfacer las restricciones en el estándar de C, sección 5.2.4.2.1». C 5.2.4.2.1 establece los requisitos para <limits.h>, incluyendo SHRT_MIN <= -32767, SHRT_MAX >= +32767, y USHRT_MAX >= 65535
    • Tenga en cuenta que una aplicación podría typedef int8_t a un estándar de aplicación definido por el tipo (y puede que en esas pocas plataformas que utilizan 16 bits char). Creo que el C++11 estándar falta algunas aclaraciones necesarias sobre cómo estas stdint.h tipos deben resolver en las sobrecargas. Tengo la sospecha de que la forma de estos tipos podrían coincidir para la resolución de sobrecarga sería definido por la implementación.
    • Sí, podría ser que falte algo (estoy más familiarizado con C de C++). C++ permite que extendido los tipos integer, algo que tomó prestado de C99. Prácticamente hablando, sin embargo, no puedo pensar en una razón para definir un extendido de tipo entero que puede ser un candidato para int8_t – a menos que, supongo, es sólo para evitar la toma de int8_t un tipo de carácter.
    • el único caso en el que puedo pensar es cuando el nativo » char tipo es de 16-bits. Incluso en ese caso, si hubo sobrecargas para ambos signed char y int, que sería el preferido de sobrecarga?
    • Si char es de 16 bits, a continuación,CHAR_BIT==16, y un byte es, por definición, de 16 bits. Aparte de los campos de bits, usted no puede tener un tipo entero menor que 1 byte. Así que en ese caso no habría int8_t. (Si usted no está convencido, piensa acerca de sizeof (int8_t).)
    • Ah, sí. Me olvidé de ese detalle.
    • Te gustaría ser capaz de confirmar con cualquier autoridad que el estándar ha no tomado medidas para hacer mi programa de salida bien definidos? No quiero suponer que usted está diciendo eso.
    • No con cualquier autoridad, no. He añadido varios senderismo en los párrafos a mi respuesta.
    • Incluso si int8_t no es un typedef para signed char, ostream::operator<<(char) es probable que sea el mejor partido durante la resolución de sobrecarga, y así que vas a tener carácter de salida de todos modos.
    • Lo que podría ser un typedef para otros que signed char o char?
    • Que __int8 que usted menciona en su respuesta (por ejemplo, MSVC tiene uno). Pero la Norma ostream clase no tiene un formato operador de inserción de sobrecarga para __int8… así que voy a usar el uno para char de todos modos.
    • Ok. No sé el «mejor partido» reglas muy bien, pero este no es el lugar para entrar en él.
    • la conversión de secuencias ordenadas por sus filas: una Coincidencia Exacta es una mejor conversión de una Promoción, que es una mejor conversión de una Conversión.» En este caso, una promoción sería [conv.prom]/1, es decir, una promoción para (unsigned) int (a partir de un tipo con una menor conversión de rango). Una conversión sería [conv.integral]/1, es decir, una conversión a cualquier tipo entero (incluyendo char). Sólo si char == uint8_t, la más viable función debe ser operator<< (char) AFAIK, más operator<< (int).
    • Creo que tienes razón.
    • Ver a Daniel de la respuesta.
    • Voigt: MSVC, de hecho, una característica intrínseca de __int8 tipo que no es un typedef para un char. Sin embargo, «__int8 tipo de datos es sinónimo de tipo char«. Consulte aquí. Usted puede verificar esto al declarar una variable de tipo __int8 y ver que el depurador se dice que es un char. Esto es bastante confuso, debo decir. No tengo idea de por qué MS lo ha hecho.
    • y amigos, presumiblemente, son anteriores a la C99 del <stdint.h>, que introdujo int8_t et al. Como suena, en lugar de ser un typedef, __int8 es una implementación palabra clave definida por el que los nombres del mismo tipo que char hace, similar a la forma en int y signed nombre del mismo tipo.
    • Tenga en cuenta que la función de estilo de fundición y static_cast no son equivalentes en el último ejemplo (la función de estilo de fundición puede legalmente desechado constness o reinterpretar)
    • A la pregunta de si uint8_t es un tipo de carácter es importante en la C, ya que los tipos de caracteres especiales de aliasing comportamientos. Una gran cantidad de código requiere un tipo que está garantizado a ser exactamente 8 bits sin relleno y acciones unsigned char‘s exención de aliasing reglas y usos uint8_t para ese propósito. Hubiera sido útil si c99 había definido un nombre como uinta8_t de 8 bits con el tipo con el alias de apoyo, [permitiendo uint8_t a ser una larga tipo sin aliasing apoyo], pero como no, un montón de código utiliza uint8_t incluso cuando aliasing de apoyo es necesario.

  3. 6

    Voy a responder a sus preguntas en orden inverso.

    Hace el estándar especifica si este tipo puede ser o será un tipo de carácter?

    Respuesta corta: int8_t es signed char en la mayoría de las plataformas más populares (GCC/Intel/Clang en Linux y Visual Studio en Windows), pero podría ser algo más que en otros.

    El tiempo de respuesta de la siguiente manera.

    Sección 18.4.1 de C++11 Estándar proporciona la sinopsis de <cstdint> que incluye los siguientes

    typedef entero con signo tipo de int8_t; //optional

    Más tarde en la misma sección, párrafo 2, dice

    El encabezado [<cstdint>] define todas las funciones, tipos y macros de la misma como 7.18 en el estándar de C.

    donde C medios estándar C99 como por 1.1/2:

    C ++ es un lenguaje de programación de propósito general basado en el lenguaje de programación C, como se describe en ISO/IEC 9899:1999 lenguajes de Programación: C (en adelante referido como el estándar de C).

    Por lo tanto, la definición de int8_t se encuentra en la Sección 7.18 del estándar C99. Más precisamente, C99 la Sección 7.18.1.1 dice

    La typedef nombre intN_t designa un entero con signo tipo con ancho de N , sin relleno de bits, y un complemento a dos de la representación. Por lo tanto, int8_t denota un entero con signo tipo con un ancho de exactamente 8 bits.

    Además, C99 la Sección 6.2.5/4 dice

    Hay cinco estándar entero con signo de tipos, designado como signed char, short int, int, long int, y long long int. (Estos y otros tipos pueden ser designado en varias maneras, como se describe en 6.7.2.) También puede ser aplicación definida por el extendido entero con signo de tipos. El estándar y extendido entero con signo de tipos son llamados colectivamente entero con signo de tipos.

    Finalmente, C99 la Sección 5.2.4.2.1 impone a los tamaños mínimos para el estándar firmado los tipos enteros. Excluyendo signed char, todos los demás son al menos 16 bits de longitud.

    Por lo tanto, int8_t es signed char o de 8 bits de longitud extendida (no estándar) firmado tipo entero.

    Tanto glibc (la biblioteca de C de GNU) y Visual Studio C biblioteca de definir int8_t como signed char. Intel y Clang, al menos en Linux, también el uso de libc y, por lo tanto, la misma se aplica a ellos. Por lo tanto, en la mayoría de plataformas populares int8_t es signed char.

    Dado este C++11 programa, debo esperar para ver un número o una letra? O no hacer con las expectativas?

    Respuesta corta: En la mayoría de las plataformas más populares (GCC/Intel/Clang en Linux y Visual Studio en Windows) que sin duda se verá la letra ‘A’. En el resto de plataformas se puede ver 65 aunque. (Gracias a DyP para señalar esto para mí.)

    En la secuela, todas las referencias son a la de C++11 (actual proyecto, N3485).

    Sección 27.4.1 proporciona la sinopsis de <iostream>, en particular, a los estados la declaración de cout:

    extern ostream cout;

    Ahora, ostream es un typedef para una plantilla de especialización de basic_ostream por la Sección 27.7.1:

    template <class charT, class traits = char_traits<charT> >
    class basic_ostream;
    
    typedef basic_ostream<char> ostream;

    Sección 27.7.3.6.4 proporciona la siguiente declaración:

    template<class traits>
    basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c);

    Si int8_t es signed char entonces es esta sobrecarga que va a ser llamado. La misma sección también se especifica que el efecto de esta convocatoria es la impresión de los caracteres (no la cantidad).

    Ahora, vamos a considerar el caso donde int8_t es un extendido firmado de tipo entero. Obviamente, la norma no especifica las sobrecargas de operator<<() para no estándar de los tipos, pero gracias a las promociones y convertions una de las sobrecargas podría aceptar la llamada. De hecho, int es de al menos 16 bits de longitud y puede representar todos los valores de int8_t. Luego de 4.5/1 da que int8_t puede ser promovido a int. Por otro lado, 4.7/1 y 4.7/2 da que int8_t puede ser convertido a signed char. Finalmente, 13.3.3.1.1 los rendimientos que la promoción es favorecido por encima de conversión durante la resolución de sobrecarga. Por lo tanto, la siguiente sobrecarga (declarado en 23.7.3.1)

    basic_ostream& basic_ostream operador::<<(int n);

    será llamado. Esto significa que, este código

    int8_t i = 65;
    std::cout << i;

    imprimirá 65.

    Actualización:

    1. Se ha corregido el post siguiente DyP‘s comentario.

    2. Se agregó el siguiente comentario sobre la posibilidad de int8_t ser un typedef para char.

    Como se dijo, el estándar C99 (Sección 6.2.5/4 citado más arriba) define la norma 5 firmado tipos enteros (char no es uno de ellos) y permite implementaciones para añadir su onw que se conocen como no estándar firmado los tipos enteros. El estándar de C++ refuerza esa definición en la Sección 3.9.1/2:

    Hay cinco estándar firmado tipos enteros : «signed char», «short int», «int», «long int», y «long long int» […] puede también ser definida por implementación extendida firmado los tipos enteros. El estándar y extendido entero con signo de tipos son llamados colectivamente entero con signo de tipos.

    Más tarde, en la misma sección, párrafo 7 dice:

    Tipos bool, char, char16_t, char32_t, wchar_t, y el signed y unsigned integer tipos son llamados colectivamente integral tipos. Un sinónimo de tipo integral, es de tipo entero.

    Por lo tanto, char es de tipo entero, pero char no es un entero con signo tipo de ni un tipo de entero sin signo y la Sección 18.4.1 (citado anteriormente) dice que int8_t, cuando está presente, es un typedef para un entero con signo tipo.

    Lo que podría ser confuso es que, dependiendo de la aplicación, char puede tomar los mismos valores que un signed char. En particular, char podría tener un signo, pero no es un signed char. Esto es dicho explícitamente en la Sección 3.9.1/1:

    […] Llanura char, signed char, y unsigned char son tres tipos distintos. […] En particular, la aplicación de una llanura char objeto puede tomar los mismos valores como signed char o un unsigned char; que uno es de aplicación definido.

    Esto también implica que char es no un entero con signo tipo definido por 3.9.1/2.

    3. Admito que mi interpretación y, específicamente, la frase «char no es un entero con signo tipo de ni un tipo de entero sin signo» es un poco controvertido.

    A la fuerza mi caso, me gustaría añadir que Stephan T. Lavavej dijo que la misma cosa aquí y Johannes Schaub – litb también se utiliza la misma frase en un comentario en este post.

    • Yo no creo que va a un error de compilación si int8_t != signed char por las dos razones siguientes: 1) int8_t podría ser un char (un tipo distinto diferente de signed char). 2) Incluso si int8_t fue un extendido de tipo entero, sería un tipo entero, ver [basic.fundamentales]/2+7. Y como [conv.prom]/1 nos dice, podría ser promovido a int o unsigned int (como int debe ser >= char >= 8 bits). Véase también Daniel respuesta.
    • Estás en lo correcto. Gracias a la integral de promociones/conversión habrá una sobrecarga de operator<< que puede tomar la llamada. Gracias por señalarlo. Voy a corregir el post. Sin embargo, como tengo entendido, int8_t no puede ser un char. Voy a añadir más información sobre este punto. Por favor, hágamelo saber lo que piensa.
    • El estado de char no es del todo claro para mí. Se trata de una tipo integral, ni firmado, ni tipo de entero sin signo. Podría ser un typedef para una extensión de tipo entero?
    • Ya he trabajado con Daniel: [al dorso.ics.rango] dice que una Promoción integral [conv.prom] será preferido a través de una integral de Conversión [conv.integral] en el cómputo de los mejores viable función (sobrecarga). Y una promoción integral de la int8_t a int es ciertamente posible (int >= 16 bits); la misma para uint8_t y unsigned int. Por lo tanto, si ha de ser convertidos, que va a ser promovido a un int y la salida será 65 (o el número) en lugar de A. Además, todavía no estoy seguro de si typedef extended_int char; typedef extended_int int8_t; es legal o no.
    • extended_int char es ilegal porque char es un tipo estándar y estándar y extendido tipos deben ser diferentes. typedef extended_int int8_t es legal. Creo, pero no estoy seguro de que (como se ha explicado en mi post), que uint8_t puede ser promovido a signed char y, por lo tanto, ‘a’ será impreso (no 65).
    • «estándar y extendido tipos deben ser diferentes» Podría por favor proporcionar una referencia? Te agradecería que. uint8_t no se puede promovido a signed char, que sólo puede ser promovido a int o unsigned int 4.5[conv.prom]/1; pero como C especifica int es >= 16 bits, que sólo puede ser promovido a int. Se puede convertir a signed char, a pesar de que, pero la promoción será preferido durante la resolución de sobrecarga [al dorso.ics.rango].
    • Tienes razón: si uint_8 no signed char, entonces puede ser promovido a int, convierten a signed char y promoción es preferible durante la resolución de sobrecarga. Por lo tanto, 65 va a ser impresa. Voy a actualizar pronto. Respecto a la estándar y extendido tipos diferentes: es implícita por [conv.rango]/1. Más específicamente, se dice, «El rango de cualquier estándar de tipo entero deberá ser mayor que el valor de cualquier tipo entero con el mismo tamaño.» Si una norma de tipo entero era un typedef para una extensión de tipo entero, entonces tendrían el mismo tamaño y rango. Gracias por la buena discusión.
    • Gracias, también, para la discusión y la referencia. También pensé en el ranking, pero yo no encuentro ninguna declaración explícita como en [basic.fundamentales]. Él es un lugar inverosímil caso, y tiendo a estar de acuerdo el typedef extended_type char; contradice la Std.

  4. 5

    El borrador de trabajo de la copia que yo tengo, N3376, especifica en [cstdint.syn] § 18.4.1 que el int tipos son típicamente typedefs.

    namespace std {
    typedef signed integer type int8_t; //optional
    typedef signed integer type int16_t; //optional
    typedef signed integer type int32_t; //optional
    typedef signed integer type int64_t; //optional
    typedef signed integer type int_fast8_t;
    typedef signed integer type int_fast16_t;
    typedef signed integer type int_fast32_t;
    typedef signed integer type int_fast64_t;
    typedef signed integer type int_least8_t;
    typedef signed integer type int_least16_t;
    typedef signed integer type int_least32_t;
    typedef signed integer type int_least64_t;
    typedef signed integer type intmax_t;
    typedef signed integer type intptr_t; //optional
    typedef unsigned integer type uint8_t; //optional
    typedef unsigned integer type uint16_t; //optional
    typedef unsigned integer type uint32_t; //optional
    typedef unsigned integer type uint64_t; //optional
    typedef unsigned integer type uint_fast8_t;
    typedef unsigned integer type uint_fast16_t;
    typedef unsigned integer type uint_fast32_t;
    typedef unsigned integer type uint_fast64_t;
    typedef unsigned integer type uint_least8_t;
    typedef unsigned integer type uint_least16_t;
    typedef unsigned integer type uint_least32_t;
    typedef unsigned integer type uint_least64_t;
    typedef unsigned integer type uintmax_t;
    typedef unsigned integer type uintptr_t; //optional
    } //namespace std

    Ya que el único requisito es que debe ser de 8 bits, entonces typedef para un char es aceptable.

  5. -1

    char/signed char/unsigned char son de tres tipos diferentes, y un char no es siempre de 8 bits. en la mayoría de plataforma todos ellos son de 8 bits entero, pero std::ostream sólo se define char versión de >> para conductas como scanf("%c", ...).

    • Son exactamente 8 bits en cada plataforma que define int8_t.
    • No exactamente, CHAR_BIT en <climits> define el número de bits en un char. Aunque no he visto ninguna plataforma con CHAR_BIT valor distinto de 8.
    • si CHAR_BIT es mayor que 8, entonces int8_t no existe en la plataforma. La Norma no permite CHAR_BIT a ser inferior a 8.

Dejar respuesta

Please enter your comment!
Please enter your name here