Des tailles minimales garanties pour les types en C?

Pouvez-vous généralement faire des hypothèses sur la taille minimale d’un type de données?

Ce que j’ai lu jusqu’à présent:

  • caractère: 1 octet
  • court: 2 octets
  • int: 2 octets, généralement 4 octets
  • long: 4 octets

flotte??? double???

Les valeurs dans float.h et limits.hlimits.h dépendantes du système?

Ceci est couvert dans l’article de Wikipedia :

Un short int ne doit pas être plus grand qu’un int .
Un int ne doit pas être plus grand qu’un long int .

Un short int doit avoir une longueur d’au moins 16 bits.
Un int doit avoir au moins 16 bits de long.
Un long int doit avoir au moins 32 bits.
Un long long int doit avoir au moins 64 bits.

La norme n’exige pas que ces tailles soient nécessairement différentes. Cela est parfaitement valable, par exemple, si les quatre types ont une longueur de 64 bits.

Oui, les valeurs dans float.h et limits.h dépendent du système. Vous ne devriez jamais émettre d’hypothèses sur la largeur d’un type, mais la norme établit des minimums. Voir les § 6.2.5 et 5.2.2.2.1 de la norme C99 .

Par exemple, la norme indique uniquement qu’un caractère doit être suffisamment grand pour contenir tous les caractères du jeu de caractères d’exécution. Cela ne dit pas à quel point c’est large.

Pour le cas en virgule flottante, la norme indique l’ordre dans lequel les largeurs des types sont données:

§6.2.5.10

Il existe trois types de flottement réels , désignés par float , double et long double . 32) L’ensemble des valeurs du type float est un sous-ensemble de l’ensemble des valeurs du type double ; l’ensemble de valeurs du type double est un sous-ensemble de l’ensemble des valeurs du type long double .

Ils ont implicitement défini ce qui est plus large que l’autre, mais pas précisément leur largeur. Le “sous-ensemble” lui-même est vague, car un long double peut avoir exactement la même plage d’un double et satisfaire à cette clause.

Ceci est assez typique de la façon dont C va et beaucoup d’en rest laissé à chaque environnement. Vous ne pouvez pas assumer, vous devez demander au compilateur.

Cependant, le nouveau C99 spécifie (dans stdint.h ) des types facultatifs de tailles minimales, tels que uint_least8_t , int_least32_t , etc.
(voir en_wikipedia_Stdint_h )

Neuf ans et toujours pas de réponse directe sur la taille minimale pour float, double, long double .


Des tailles minimales garanties pour les types en C?

Pour le type virgule flottante

D’un sharepoint vue pratique, la taille minimale float est de 32 bits et la taille double 64 bits . C permet au double et au double long double de partager des caractéristiques similaires, de sorte qu’un long double pourrait être aussi petit qu’un double . Exemple 1

J’imagine qu’un double 48 bits conforme C aurait pu exister – mais je n’en connais aucun.


Maintenant, imaginons que notre riche oncle meurt et nous laisse une fortune pour financer le développement et la promotion culturelle de http://www.smallest_C_float.com .

C spécifie:

1) La plage finie de float est au moins [1E-37… 1E + 37]. Voir FLT_MIN, FLT_MAX

2) (1.0f + FLT_EPSILON) – 1.0f <= 1E-5 .

3) float supporte les valeurs positives et négatives.

 Let X: Digit 1-9 Let Y: Digit 0-9 Let E: value -37 to 36 Let S: + or - Let b: 0 or 1 

Notre float pourrait représenter au minimum toutes les combinaisons, en utilisant la base 10, de SX.YYYYY*10^E

0.0 et ±1E+37 sont également nécessaires (3 de plus). Nous n'avons pas besoin de -0.0, sous-normales, ± infini ni de non-nombres.

Cela correspond à 2 * 9 * 10 ^ 5 * 74 + 3 combinaisons ou à 133 200 003 qui nécessitent au moins 27 bits pour être codés - d’une manière ou d’une autre . Rappelez-vous que l'objective est de taille minimale.

Avec une approche classique en base 2, on peut supposer un 1 implicite et obtenir des combinaisons S1.bbbb_bbbb_bbbb_bbbb_b * 2 ^ e ou 2 * 2 ^ 17 * 226 ou 26 bits.

Si nous essayons la base 16, il nous faut alors environ 2 * 15 * 16 ^ (4 ou 5) * 57 combinaisons ou au moins 26 à 30 bits.

Conclusion: le float AC float nécessite au moins 26 bits de codage.


Le double un C n'a pas besoin d'exprimer une plage exponentielle supérieure à celle de float ; 1E-9 .

S1.bbbb_bbbb_bbbb_bbbb_ bbbb_ bbbb_ bbbb_bb * 2 ^ e -> 2 * 2 ^ 30 * 226 combinaisons ou 39 bits.


Sur notre ordinateur Imaginez-si-vous-voudrez , nous pourrions avoir un caractère de 13 bits et ainsi encoder des valeurs float, double, long double sans rembourrage. Ainsi, nous pouvons réaliser un float 26 bits non double, long double 39 bits.


1 : Microsoft Visual C ++ pour x86, ce qui rend long double synonyme de double

Souvent, les développeurs qui posent ce type de question s’occupent de la mise en place d’une struct pour correspondre à une structure de mémoire définie (comme pour un protocole de message). L’hypothèse est que le langage devrait spécifier directement le format des champs 16, 24, 32 bits, etc. à cette fin.

Cela est courant et acceptable pour les langages d’assemblage et d’autres langages spécifiques à l’application étroitement liés à une architecture de processeur particulière, mais pose parfois problème dans un langage à usage général qui peut viser une architecture qui ne sait pas quoi.

En fait, le langage C n’était pas destiné à une implémentation matérielle particulière. Il a été spécifié de manière générale afin qu’un implémenteur du compilateur C puisse s’adapter correctement aux réalités d’un processeur particulier. Une architecture matérielle Frankenstein composée d’octets de 9 bits, de mots de 54 bits et d’adresses de mémoire de 72 bits est facilement mappée – et sans ambiguïté – sur les fonctionnalités C. ( char est de 9 bits; short int , int et long int 54 bits.)

Cette généralité est la raison pour laquelle la spécification C dit quelque chose à l’effet de “n’attendez pas beaucoup sur les tailles d’ints supérieures à sizeof (char) <= sizeof (int court) <= sizeof (int) <= sizeof (long int). " Cela implique que les caractères pourraient avoir la même taille que les longs!

La réalité actuelle est, et l’avenir semble être le même, que le logiciel exige que les architectures fournissent des octets sur 8 bits et que les mots de mémoire adressables sous forme d’octets individuels. Cela n’a pas toujours été le cas. Il n’y a pas si longtemps, j’ai travaillé sur l’architecture CDC Cyber, qui comporte des “octets” de 6 bits et des mots de 60 bits. AC mise en œuvre sur ce serait intéressant. En fait, cette architecture est responsable de la sémantique d’emballage étrange de Pascal – si quelqu’un s’en souvient.

Si vous ne voulez pas vérifier la taille (en multiples de caractères) de tout type sur votre système / plate-forme est vraiment la taille que vous attendez, vous pouvez faire:

 enum CHECK_FLOAT_IS_4_CHARS { IF_THIS_FAILS_FLOAT_IS_NOT_4_CHARS = 1/(sizeof(float) == 4) }; 

C99 N1256 projet standard

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

C99 spécifie deux types de garanties entières:

  • taille minimum garantie
  • tailles relatives entre les types

Garanties relatives

6.2.5 Types :

8 Pour deux types entiers avec le même niveau de signature et un rang de conversion d’entier différent (voir 6.3.1.1), la plage de valeurs du type avec un rang de conversion d’entier plus petit est une sous-gamme des valeurs de l’autre type.

et 6.3.1.1 Des booléens, des caractères et des entiers déterminent les rangs de conversion relatifs:

1 Chaque type d’entier a un rang de conversion d’entier défini comme suit:

  • Le rang de long long int doit être supérieur au rang de long int, qui doit être supérieur au rang de int, qui doit être supérieur au rang de short int, qui doit être supérieur au rang de char signé.
  • Le rang de tout type entier non signé doit être égal au rang du type entier signé signé, le cas échéant.
  • Pour tous les types entiers T1, T2 et T3, si T1 a un rang supérieur à T2 et T2 a un rang supérieur à T3, alors T1 a un rang supérieur à T3.

Dimensions minimales absolues

Mentionné par https://stackoverflow.com/a/1738587/895245 , voici la citation pour plus de commodité.

5.2.4.2.1 Tailles des types entiers :

1 […] Leurs valeurs définies pour la mise en œuvre doivent être égales ou supérieures en magnitude (valeur absolue) à celles indiquées […]

  • UCHAR_MAX 255 // 2 8 – 1
  • USHRT_MAX 65535 // 2 16 – 1
  • UINT_MAX 65535 // 2 16 – 1
  • ULONG_MAX 4294967295 // 2 32 – 1
  • ULLONG_MAX 18446744073709551615 // 2 64 – 1

Point flottant

Si la macro __STDC_IEC_559__ est définie, les types IEEE sont garantis pour chaque type C, même si long double a quelques possibilités: Est-il prudent de supposer que la virgule flottante est représentée à l’aide des flottants IEEE754 en C?

Citer la norme donne ce qui est défini comme étant “la bonne réponse” mais cela ne reflète pas réellement la façon dont les programmes sont écrits.

Les gens font des suppositions tout le temps que char est de 8 bits, short est de 16, int est de 32, long est de 32 ou 64 et long long est de 64.

Ces hypothèses ne sont pas une bonne idée mais vous ne serez pas viré pour les avoir faites.

En théorie, peut être utilisé pour spécifier des types à largeur de bit fixe, mais vous devez en rechercher un pour Microsoft. ( Voir ici pour un fichier stdint.h .) L’un des problèmes est que C ++ n’a techniquement besoin que de la compatibilité C89 pour être une implémentation conforme; même pour C simple, C99 n’est pas entièrement pris en charge, même en 2009.

Il n’est également pas exact de dire qu’il n’y a pas de spécification de largeur pour char . La norme évite simplement de dire si elle est signée ou non. Voici ce que dit réellement C99:

  • nombre de bits pour le plus petit object qui n’est pas un champ de bits (octet)
    CHAR_BIT 8
  • valeur minimale pour un object de type char signé
    SCHAR_MIN -127 // – (2 7 – 1)
  • valeur maximale pour un object de type char signé
    SCHAR_MAX +127 // 2 7 – 1
  • valeur maximale pour un object de type char non signé
    UCHAR_MAX 255 // 2 8 – 1

La plupart des bibliothèques définissent quelque chose comme ceci:

 #ifdef MY_ARCHITECTURE_1 typedef unsigned char u_int8_t; typedef short int16_t; typedef unsigned short u_int16_t; typedef int int32_t; typedef unsigned int u_int32_t; typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned long u_long; typedef unsigned short u_short; #endif 

vous pouvez ensuite utiliser ces typedef dans vos programmes au lieu des types standard.