web-dev-qa-db-fra.com

En quoi la norme C ++ définit-elle la taille de type int, long?

Je recherche des informations détaillées sur la taille des types de base C++. Je sais que cela dépend de l'architecture (16 bits, 32 bits, 64 bits) et du compilateur.

Mais existe-t-il des normes pour C++?

J'utilise Visual Studio 2008 sur une architecture 32 bits. Voici ce que je reçois:

char  : 1 byte
short : 2 bytes
int   : 4 bytes
long  : 4 bytes
float : 4 bytes
double: 8 bytes

J'ai essayé de trouver, sans grand succès, des informations fiables indiquant la taille de char, short, int, long, double, float (et d'autres types auxquels je n'avais pas pensé) sous différentes architectures et compilateurs.

669
Jérôme

La norme C++ ne spécifie pas la taille des types intégraux en octets, mais spécifie les plages minimales qu'ils doivent pouvoir contenir. Vous pouvez déduire la taille minimale en bits de la plage requise. Vous pouvez en déduire la taille minimale en octets et la valeur de la macro CHAR_BIT que définit le nombre de bits dans un octet (dans les plates-formes les plus obscures, il s'agit de 8, et il ne peut en être moins plus de 8).

Une contrainte supplémentaire pour char est que sa taille est toujours de 1 octet, ou CHAR_BIT bits (d'où son nom).

Les plages minimales requises par la norme (page 22) sont les suivantes:

et plages de types de données sur MSDN :

  1. signed char: -127 à 127 (remarque, pas -128 à 127; cela prend en charge les plates-formes à complément et signe-magnitude)
  2. unsigned char: 0 à 255
  3. "plain" char: même plage que signed char ou unsigned char, défini par l'implémentation
  4. signed short: -32767 à 32767
  5. unsigned short: 0 à 65535
  6. signed int: -32767 à 32767
  7. unsigned int: 0 à 65535
  8. signed long: -2147483647 à 2147483647
  9. unsigned long: 0 to 4294967295
  10. signed long long: -9223372036854775807 à 9223372036854775807
  11. unsigned long long: 0 to 18446744073709551615

Une implémentation C++ (ou C) peut définir la taille d'un type en octets sizeof(type) en n'importe quelle valeur, tant que

  1. l'expression sizeof(type) * CHAR_BIT donne un nombre de bits suffisant pour contenir les plages requises, et
  2. l'ordre de type est toujours valide (par exemple, sizeof(int) <= sizeof(long)).

Les plages spécifiques à l'implémentation se trouvent dans l'en-tête <limits.h> en C ou <climits> en C++ (ou mieux encore, le modèle std::numeric_limits dans l'en-tête <limits>).

Par exemple, voici comment trouver la plage maximale pour int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C++ :

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();
661
Alex B

Pour les systèmes 32 bits, le standard "de facto" est ILP32 - int, long et le pointeur sont des quantités 32 bits.

Pour les systèmes 64 bits, la norme principale 'de facto' d'Unix est LP64 - long et le pointeur sont à 64 bits (mais int est à 32 bits). La norme Windows 64 bits est LLP64 - long long et le pointeur sont en 64 bits (mais long et int en 32 bits).

À un moment donné, certains systèmes Unix utilisaient une organisation ILP64.

Aucune de ces normes de facto n'est régie par la norme C (ISO/IEC 9899: 1999), mais toutes sont autorisées par celle-ci.

Et, par définition, sizeof(char) est 1, nonobstant le test du script de configuration Perl.

Notez qu'il y avait des machines (Crays) où CHAR_BIT était beaucoup plus grand que 8. Cela signifiait, IIRC, que sizeof(int) était également 1, parce que char et int étaient 32 -bit.

230
Jonathan Leffler

En pratique, rien de tel. Vous pouvez souvent vous attendre à ce que std::size_t représente la taille de l'entier natif non signé sur l'architecture actuelle. c'est-à-dire 16 bits, 32 bits ou 64 bits, mais ce n'est pas toujours le cas, comme indiqué dans les commentaires de cette réponse.

En ce qui concerne tous les autres types intégrés, cela dépend vraiment du compilateur. Voici deux extraits du brouillon actuel de la dernière norme C++:

Il existe cinq types d'entiers signés standard: char signé, int court, int, long int et long long int. Dans cette liste, chaque type fournit au moins autant de mémoire que ceux qui le précèdent dans la liste.

Pour chacun des types d'entiers signés standard, il existe un type d'entier non signé standard correspondant (mais différent): unsigned char, unsigned short int, unsigned int, unsigned long int et unsigned longnt int, chacun occupant la même quantité de stockage et a les mêmes exigences d'alignement.

Si vous le souhaitez, vous pouvez affirmer statistiquement (à la compilation) la taille de ces types fondamentaux. Cela incitera les gens à réfléchir au portage de votre code si la taille des hypothèses change.

87
John Leidegren

Il y a la norme.

La norme C90 exige que

sizeof(short) <= sizeof(int) <= sizeof(long)

La norme C99 exige que

sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Voici les spécifications C99 . Page 22 détaille les tailles de différents types d'intégraux.

Voici les tailles de type int (bits) pour les plates-formes Windows:

Type           C99 Minimum     Windows 32bit
char           8               8
short          16              16
int            16              32
long           32              32
long long      64              64

Si vous êtes préoccupé par la portabilité ou si vous voulez que le nom du type reflète la taille, vous pouvez consulter l'en-tête <inttypes.h>, où les macros suivantes sont disponibles:

int8_t
int16_t
int32_t
int64_t

int8_t est garanti à 8 bits et int16_t est à 16 bits, etc.

78
yinyueyouge

Si vous avez besoin de types de taille fixe, utilisez des types tels que uint32_t (entier non signé 32 bits) défini dans stdint.h . Ils sont spécifiés dans C99 .

38
Ben

Mise à jour: C++ 11 a officiellement intégré les types de TR1 dans la norme:

  • long long int
  • non signé long long int

Et les types "dimensionnés" de <cstdint>

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • (et les homologues non signés).

De plus, vous obtenez:

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • Plus les homologues non signés.

Ces types représentent les types d'entiers les plus petits avec au moins le nombre de bits spécifié. De même, il existe les types entiers "les plus rapides" avec au moins le nombre de bits spécifié:

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • Plus les versions non signées.

Ce que "rapide" signifie, s’il ya lieu, dépend de la mise en oeuvre. Ce n’est pas nécessairement le plus rapide à toutes fins.

35
Brian Neal

Le C++ Standard le dit comme ceci:

3.9.1, §2:

Il existe cinq types d'entiers signés: "char signé", "int court", "int", "long int" et "long long int". Dans cette liste, chaque type fournit au moins autant de mémoire que ceux qui le précèdent dans la liste. Plain ints ont la taille naturelle suggérée par l'architecture de l'environnement d'exécution (44); les autres types d'entiers signés sont fournis pour répondre à des besoins particuliers.

(44) c'est-à-dire assez grand pour contenir n'importe quelle valeur dans la plage de INT_MIN et INT_MAX, comme défini dans l'en-tête <climits>.

La conclusion: cela dépend de l'architecture sur laquelle vous travaillez. Toute autre hypothèse est fausse.

19
Jérôme Radix

Non, il n'y a pas de standard pour les tailles de caractères. Standard exige seulement que:

sizeof(short int) <= sizeof(int) <= sizeof(long int)

La meilleure chose à faire si vous voulez des variables de taille fixe est d’utiliser des macros comme ceci:

#ifdef SYSTEM_X
  #define Word int
#else
  #define Word long int
#endif

Ensuite, vous pouvez utiliser Word pour définir vos variables. Ce n’est pas que j’aime ça, mais c’est le moyen le plus portable.

12
Emiliano

Nous sommes autorisés à définir un synonyme pour le type afin de pouvoir créer notre propre "standard".

Sur une machine dans laquelle sizeof (int) == 4, on peut définir:

typedef int int32;

int32 i;
int32 j;
...

Ainsi, lorsque nous transférons le code sur une autre machine où la taille de long int est 4, nous pouvons simplement redéfinir la seule occurrence de int.

typedef long int int32;

int32 i;
int32 j;
...
10
milan-j

Pour les nombres à virgule flottante il existe une norme (IEEE754) : les flottants sont de 32 bits et les doubles de 64. C'est une norme matérielle, pas une norme C++, de sorte que les compilateurs pourraient théoriquement définir des flottants et des doubles. taille, mais dans la pratique, je n’ai jamais vu d’architecture utilisant autre chose.

8
Crashworks

Il existe une norme spécifiée dans les divers documents de normalisation (ISO, ANSI, etc.).

Wikipedia a une grande page expliquant les différents types et le maximum qu’ils peuvent stocker: Integer in Computer Science.

Cependant, même avec un compilateur C++ standard, vous pouvez le découvrir relativement facilement en utilisant l'extrait de code suivant:

#include <iostream>
#include <limits>


int main() {
    // Change the template parameter to the various different types.
    std::cout << std::numeric_limits<int>::max() << std::endl;
}

La documentation pour std :: numeric_limits se trouve sur Roguewave . Il inclut une pléthore d'autres commandes que vous pouvez appeler pour connaître les différentes limites. Cela peut être utilisé avec n'importe quel type arbitraire qui porte la taille, par exemple std :: streamsize.

La réponse de John contient la meilleure description, car ils sont garantis. Quelle que soit la plate-forme sur laquelle vous vous trouvez, il existe une autre bonne page qui donne plus de détails sur le nombre de bits que chaque type DOIT contenir: int types , qui sont définis dans la norme.

J'espère que ça aide!

7
X-Istence
7
Andrew

Vous pouvez utiliser:

cout << "size of datatype = " << sizeof(datatype) << endl;

datatype = int, long int etc. Vous pourrez voir la taille du type de données que vous tapez.

7

Lorsqu'il s'agit de types intégrés pour différentes architectures et différents compilateurs, exécutez simplement le code suivant sur votre architecture avec votre compilateur pour voir ce qu'il génère. La figure ci-dessous montre ma sortie buntu 13.04 (Raring Ringtail) 64 bits + ++ 4.7.3. Veuillez également noter les réponses ci-dessous, c’est pourquoi la sortie est ordonnée en tant que telle:

"Il existe cinq types d'entiers signés standard: char signé, int court, int, long int et long long int. Dans cette liste, chaque type fournit au moins autant d'espace de stockage que ceux qui le précèdent."

#include <iostream>

int main ( int argc, char * argv[] )
{
  std::cout<< "size of char: " << sizeof (char) << std::endl;
  std::cout<< "size of short: " << sizeof (short) << std::endl;
  std::cout<< "size of int: " << sizeof (int) << std::endl;
  std::cout<< "size of long: " << sizeof (long) << std::endl;
  std::cout<< "size of long long: " << sizeof (long long) << std::endl;

  std::cout<< "size of float: " << sizeof (float) << std::endl;
  std::cout<< "size of double: " << sizeof (double) << std::endl;

  std::cout<< "size of pointer: " << sizeof (int *) << std::endl;
}


size of char: 1
size of short: 2
size of int: 4
size of long: 8
size of long long: 8
size of float: 4
size of double: 8
size of pointer: 8
7
bjackfly

Comme mentionné, la taille devrait refléter l'architecture actuelle. Vous pouvez faire un tour dans limits.h si vous voulez voir comment votre compilateur actuel gère les choses.

3
John T

Comme d’autres ont répondu, les "normes" laissent tous la plupart des détails sous "implémentation définie" et indiquent seulement que le type "char" est au moins "char_bis" large et que "char <= short <= int <= long < = long long "(float et double sont à peu près cohérents avec les normes à virgule flottante IEEE, et long double est généralement identique à double - mais peut être plus grand pour les implémentations plus récentes).

Une raison de ne pas avoir de valeurs très spécifiques et exactes est due au fait que des langages tels que C/C++ ont été conçus pour être portables sur un grand nombre de plates-formes matérielles - y compris les systèmes informatiques dans lesquels la taille du mot "char" peut être de 4 bits ou 7 bits, ou même une valeur autre que les ordinateurs "8/16/32/64 bits" auxquels l'utilisateur de l'ordinateur à la maison est exposé. (La taille des mots signifie ici le nombre de bits sur lesquels le système fonctionne normalement - Encore une fois, ce n'est pas toujours 8 bits, contrairement à ce que les utilisateurs d'ordinateurs domestiques peuvent espérer.)

Si vous avez vraiment besoin d'un objet (au sens d'une série de bits représentant une valeur intégrale) d'un nombre spécifique de bits, la plupart des compilateurs ont une méthode pour le spécifier; Mais ce n’est généralement pas portable, même entre compilateurs de la société ame mais pour différentes plates-formes. Certaines normes et pratiques (en particulier limits.h et autres) sont suffisamment communes pour que la plupart des compilateurs soient en mesure de déterminer le type le mieux adapté pour une plage de valeurs spécifique, mais pas le nombre de bits utilisés. (C’est-à-dire que si vous savez que vous devez conserver des valeurs comprises entre 0 et 127, vous pouvez déterminer que votre compilateur prend en charge un type "int8" de 8 bits, ce qui suffira pour contenir toute la plage souhaitée, mais pas comme un fichier. type "int7" qui correspondrait exactement à 7 bits.)

Remarque: De nombreux packages source Un * x ont utilisé le script "./configure" qui analysera les capacités du compilateur/système et générera un Makefile et un fichier config.h appropriés. Vous pouvez examiner certains de ces scripts pour voir comment ils fonctionnent et comment ils analysent les fonctionnalités du compilateur/du système et suivent leur exemple.

2
C. M.

Si vous êtes intéressé par une solution purement C++, j'ai utilisé des modèles et uniquement du code standard C++ pour définir les types au moment de la compilation en fonction de leur taille en bits. Cela rend la solution portable entre les compilateurs.

L'idée est très simple: créez une liste contenant les types char, int, court, long, long long (versions signées et non signées) et analysez la liste et, à l'aide du modèle numeric_limits, sélectionnez le type avec une taille donnée.

En incluant cet en-tête, vous avez 8 types: stdtype :: int8, stdtype :: int16, stdtype :: int32, stdtype :: int64, stdtype :: uint8, stdtype :: uint16, stdtype :: uint32, stdtype :: uint64.

Si un type ne peut pas être représenté, il sera évalué à stdtype :: null_type également déclaré dans cet en-tête.

LE CODE CI-DESSOUS IS DONNE SANS GARANTIE, VEUILLEZ LIRE VÉRIFIER.
JE SUIS NOUVEAU AT METAPROGRAMMANT AUSSI, NE PENSEZ PAS A EDIT ET CORRIGE CE CODE.
Testé avec DevC++ (donc une version de gcc autour de 3.5)

#include <limits>

namespace stdtype
{
    using namespace std;


    /*
     * THIS IS THE CLASS USED TO SEMANTICALLY SPECIFY A NULL TYPE.
     * YOU CAN USE WHATEVER YOU WANT AND EVEN DRIVE A COMPILE ERROR IF IT IS 
     * DECLARED/USED.
     *
     * PLEASE NOTE that C++ std define sizeof of an empty class to be 1.
     */
    class null_type{};

    /*
     *  Template for creating lists of types
     *
     *  T is type to hold
     *  S is the next type_list<T,S> type
     *
     *  Example:
     *   Creating a list with type int and char: 
     *      typedef type_list<int, type_list<char> > test;
     *      test::value         //int
     *      test::next::value   //char
     */
    template <typename T, typename S> struct type_list
    {
        typedef T value;
        typedef S next;         

    };




    /*
     * Declaration of template struct for selecting a type from the list
     */
    template <typename list, int b, int ctl> struct select_type;


    /*
     * Find a type with specified "b" bit in list "list"
     *
     * 
     */
    template <typename list, int b> struct find_type
    {   
        private:
            //Handy name for the type at the head of the list
            typedef typename list::value cur_type;

            //Number of bits of the type at the head
            //CHANGE THIS (compile time) exp TO USE ANOTHER TYPE LEN COMPUTING
            enum {cur_type_bits = numeric_limits<cur_type>::digits};

        public:
            //Select the type at the head if b == cur_type_bits else
            //select_type call find_type with list::next
            typedef  typename select_type<list, b, cur_type_bits>::type type;
    };

    /*
     * This is the specialization for empty list, return the null_type
     * OVVERRIDE this struct to ADD CUSTOM BEHAVIOR for the TYPE NOT FOUND case
     * (ie search for type with 17 bits on common archs)
     */
    template <int b> struct find_type<null_type, b>
    {   
        typedef null_type type;

    };


    /*
     * Primary template for selecting the type at the head of the list if
     * it matches the requested bits (b == ctl)
     *
     * If b == ctl the partial specified templated is evaluated so here we have
     * b != ctl. We call find_type on the next element of the list
     */
    template <typename list, int b, int ctl> struct select_type
    {   
            typedef  typename find_type<typename list::next, b>::type type; 
    };

    /*
     * This partial specified templated is used to select top type of a list
     * it is called by find_type with the list of value (consumed at each call)
     * the bits requested (b) and the current type (top type) length in bits
     *
     * We specialice the b == ctl case
     */
    template <typename list, int b> struct select_type<list, b, b>
    {
            typedef typename list::value type;
    };


    /*
     * These are the types list, to avoid possible ambiguity (some weird archs)
     * we kept signed and unsigned separated
     */

    #define UNSIGNED_TYPES type_list<unsigned char,         \
        type_list<unsigned short,                           \
        type_list<unsigned int,                             \
        type_list<unsigned long,                            \
        type_list<unsigned long long, null_type> > > > >

    #define SIGNED_TYPES type_list<signed char,         \
        type_list<signed short,                         \
        type_list<signed int,                           \
        type_list<signed long,                          \
        type_list<signed long long, null_type> > > > >



    /*
     * These are acutally typedef used in programs.
     * 
     * Nomenclature is [u]intN where u if present means unsigned, N is the 
     * number of bits in the integer
     *
     * find_type is used simply by giving first a type_list then the number of 
     * bits to search for.
     *
     * NB. Each type in the type list must had specified the template 
     * numeric_limits as it is used to compute the type len in (binary) digit.
     */
    typedef find_type<UNSIGNED_TYPES, 8>::type  uint8;
    typedef find_type<UNSIGNED_TYPES, 16>::type uint16;
    typedef find_type<UNSIGNED_TYPES, 32>::type uint32;
    typedef find_type<UNSIGNED_TYPES, 64>::type uint64;

    typedef find_type<SIGNED_TYPES, 7>::type    int8;
    typedef find_type<SIGNED_TYPES, 15>::type   int16;
    typedef find_type<SIGNED_TYPES, 31>::type   int32;
    typedef find_type<SIGNED_TYPES, 63>::type   int64;

}
1
user781847

Comme vous l'avez mentionné, cela dépend en grande partie du compilateur et de la plate-forme. Pour cela, vérifiez la norme ANSI, http://home.att.net/~jackklein/c/inttypes.html

Voici celui du compilateur Microsoft: plages de types de données.

0
atVelu

Je remarque que toutes les autres réponses ici se sont concentrées presque exclusivement sur les types intégraux, alors que le questionneur a également posé des questions sur les points flottants.

Je ne pense pas que la norme C++ l'exige, mais les compilateurs des plates-formes les plus courantes de nos jours suivent généralement la norme IEEE754 pour leurs nombres à virgule flottante. Cette norme spécifie quatre types de virgule flottante binaire (ainsi que certains formats BCD, que je n'ai jamais vus en charge dans les compilateurs C++):

  • Demi précision (binaire 16) - signification 11 bits, plage des exposants de -14 à 15
  • Précision simple (binaire32) - Signification 24 bits, plage des exposants de -126 à 127
  • Double précision (binary64) - signification 53 bits, plage des exposants de -1022 à 1023
  • Quadruple précision (binary128) - signification de 113 bits, plage de l'exposant de -16382 à 16383

Comment cela mappe-t-il sur les types C++, alors? Généralement, la float utilise une précision simple; ainsi, sizeof(float) = 4. Ensuite, double utilise la double précision (je pense que c'est la source du nom double), et long double peut être une précision double ou quadruple (c'est quadruple sur mon système, mais sur 32 bits systèmes, il peut être double). Je ne connais aucun compilateur offrant des virgules flottantes en semi-précision.

En résumé, c'est l'habituel:

  • sizeof(float) = 4
  • sizeof(double) = 8
  • sizeof(long double) = 8 ou 16
0
celticminstrel

De Alex B Le standard C++ ne spécifie pas la taille en octets des types intégraux, mais il spécifie des plages minimales qu'ils doivent pouvoir contenir. Vous pouvez déduire la taille minimale en bits de la plage requise. Vous pouvez en déduire la taille minimale en octets et la valeur de la macro CHAR_BIT qui définit le nombre de bits dans un octet (sur toutes les plates-formes, sauf la plus obscure, il s'agit de 8, et il ne peut être inférieur à 8).

Une contrainte supplémentaire pour char est que sa taille est toujours de 1 octet ou de bits CHAR_BIT (d'où son nom).

Les plages minimales requises par la norme (page 22) sont les suivantes:

et plages de types de données sur MSDN:

caractère signé: -127 à 127 (remarque, pas -128 à 127; cela concerne les plates-formes complémentaires de 1) caractère non signé: 0 à 255 caractère "ordinaire": -127 à 127 ou 0 à 255 (dépend de la signature de caractère par défaut) signé short: -32767 à 32767 unsigned short: 0 à 65535 signé int: -32767 à 32767 unsigned int: 0 à 65535 signé long: -2147483647 à 2147483647 long non signé: 0 à 4294967295 signé long long: -92233720364747775775797 0 à 18446744073709551615 Une implémentation C++ (ou C) peut définir la taille d'un type en octets sizeof (type) à n'importe quelle valeur, tant que

l'expression sizeof (type) * CHAR_BIT correspond au nombre de bits suffisant pour contenir les plages requises, et l'ordre du type est toujours valide (par exemple, sizeof (int) <= sizeof (long)). Les plages spécifiques à l'implémentation peuvent être trouvées dans l'en-tête en C, ou en C++ (ou mieux encore, std :: numeric_limits avec un modèle dans l'en-tête).

Par exemple, voici comment trouver la plage maximale pour int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

C’est exact, mais vous aviez également raison de dire que: char: 1 octet court: 2 octets int: 4 octets long: 4 octets float: 4 octets double: 8 octets

Étant donné que les architectures 32 bits sont toujours les options par défaut et les plus utilisées, elles conservent ces tailles standard depuis la période antérieure à 32 bits, lorsque la mémoire était moins disponible, et pour la compatibilité avec les versions antérieures et la normalisation, elle est restée la même. Même les systèmes 64 bits ont tendance à les utiliser et ont des extensions/modifications. Veuillez vous référer à ceci pour plus d'informations:

http://en.cppreference.com/w/cpp/language/types

0
JCoder
unsigned char bits = sizeof(X) << 3;

X est un char, int, long etc .. vous donnera une taille de X en bits.

0
user3154672