Besoin de vos lumières, oh suprêmes programmeurs qui hantent ces couloirs :)
J'étais en train de parler prog avec Yoshi, quand soudain, on s'est demandé ce que voulait dire le type long long en C.
Je me suis souvenu qu'en C, un entier avait une taille dépendante de l'architecture du processeur.
Ainsi, un int est codé sur 16 bits pour un vieux processeur 16 bits, sur 32 bits pour un processeur commun de 32 bits et sur 64 bits pour les nouveaux processeurs 64 bits.
Donc voilà, dans la plupart des cas, un int serait codé sur 32 bits, puisque c'est encore l'architecture la plus courante.
Idem pour les
unsigned qui sont juste strictement positifs et ont leur propre algèbre, bref ils ne changent en rien le nombre de bits de l'encodage.
J'ai aussi entendu dire qu'à l'époque, un entier de type long était plus long qu'un entier de type int, mais que ce n'est plus le cas de nos jour. Mm ok, mais depuis quelle norme ? C89 ou C99 ?
Il y a quelques mois, j'avais zyeuté le code source de la Glib et j'avais appris qu'il y avait moyen de définir des types de taille fixe, peu importe l'architecture du processeur, en jouant avec des préfixes de int (short, long, long long, ...). D'après le code source (http://git.gnome.org/browse/glib/tree/glib/glibconfig.h.win32.in) :
Citation de: glib/glibconfig.h.win32.in
typedef signed char gint8;
typedef unsigned char guint8;
typedef signed short gint16;
typedef unsigned short guint16;
typedef signed int gint32;
typedef unsigned int guint32;
#ifndef _MSC_VER
G_GNUC_EXTENSION typedef signed long long gint64;
G_GNUC_EXTENSION typedef unsigned long long guint64;
#else /* _MSC_VER */
typedef signed __int64 gint64;
typedef unsigned __int64 guint64;
#endif /* _MSC_VER */
et la suite, dans
gtypes.h :
Citation de: glib/gtypes.h
/* Provide type definitions for commonly used types.
* These are useful because a "gint8" can be adjusted
* to be 1 byte (8 bits) on all platforms. Similarly and
* more importantly, "gint32" can be adjusted to be
* 4 bytes (32 bits) on all platforms.
*/
typedef char gchar;
typedef short gshort;
typedef long glong;
typedef int gint;
typedef gint gboolean;
typedef unsigned char guchar;
typedef unsigned short gushort;
typedef unsigned long gulong;
typedef unsigned int guint;
Donc, j'en conclu :
-
(unsigned) int donne un entier de taille variable (dépend architecture)
-
(un)signed short donne un entier sur 16 bits
-
(un)signed int donne un entier sur 32 bits (ah déjà une incohérence, j'en reparle plus loin)
-
(un)signed long long donne un entier sur 64 bits, sous Windows
-
(un)signed __int64 donne pareil, sous les autres OS
Si je comprends bien,
signed force le nombre de bits, puisque
signed int est codé sur 32 et
int sur un nombre variable de bits.
Mais alors, pourquoi
unisigned int est utilisé à la fois pour un entier non signé sur 32 bits et aussi pour un entier non signé sur nombre variable de bits :o ???
Second bémol, il me semblait qu'on devait écrire
short int et non
short tout court (pas fait exprès :mrgreen:) !? Serait-ce comme pour
long, qu'on utilise. Pourtant j'ai déjà entendu parler de
long int. Quelle est la différence ? Depuis quelle norme ?
Là, un doute me prend, je vais zyeuter le code source de la SDL qui, d'après mes souvenirs, définissait le même genre d'entiers à taille fixe. J'y trouve dans
ce fichier :
Citation de: include/SDL_stdinc.h
67 #if defined(HAVE_INTTYPES_H)
68 # include <inttypes.h>
69 #elif defined(HAVE_STDINT_H)
70 # include <stdint.h>
71 #endif
...
122 /**
123 * \brief A signed 8-bit integer type.
124 */
125 typedef int8_t Sint8;
126 /**
127 * \brief An unsigned 8-bit integer type.
128 */
129 typedef uint8_t Uint8;
130 /**
131 * \brief A signed 16-bit integer type.
132 */
133 typedef int16_t Sint16;
134 /**
135 * \brief An unsigned 16-bit integer type.
136 */
137 typedef uint16_t Uint16;
138 /**
139 * \brief A signed 32-bit integer type.
140 */
141 typedef int32_t Sint32;
142 /**
143 * \brief An unsigned 32-bit integer type.
144 */
145 typedef uint32_t Uint32;
146
147 /**
148 * \brief A signed 64-bit integer type.
149 */
150 typedef int64_t Sint64;
151 /**
152 * \brief An unsigned 64-bit integer type.
153 */
154 typedef uint64_t Uint64;
155
156 /*@}*//*Basic data types*/
J'en conclu que les types
(u)intXX_t sont définis dans l'un de entêtes
inttypes.h ou
stdint.h de la lib standard.
J'apprends par ailleurs qu'ils n'ont été introduits qu'à la norme C99, ce qui ne me plait pas beaucoup, m'enfin, passons (bien qu'étonnant pour une lib qui se veut très rétro-compatible).
Regardons ensemble un extrait de la spécification de l'entête
stdint.h :
Citation de: specification de stdint.h
Integer Types
When typedef names differing only in the absence or presence of the initial u are defined, they shall denote corresponding signed and unsigned types as described in the ISO/IEC 9899:1999 standard, Section 6.2.5; an implementation providing one of these corresponding types shall also provide the other.
In the following descriptions, the symbol N represents an unsigned decimal integer with no leading zeros (for example, 8 or 24, but not 04 or 048).
*
Exact-width integer types
The typedef name int N _t designates a signed integer type with width N, no padding bits, and a two's-complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.
The typedef name uint N _t designates an unsigned integer type with width N. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits.
[CX] [Option Start] The following types are required:
int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t
[Option End]
If an implementation provides integer types with width 64 that meet these requirements, then the following types are required: int64_t uint64_t
[CX] [Option Start] In particular, this will be the case if any of the following are true:
o
The implementation supports the _POSIX_V7_ILP32_OFFBIG programming environment and the application is being built in the _POSIX_V7_ILP32_OFFBIG programming environment (see the Shell and Utilities volume of POSIX.1-2008, c99, Programming Environments).
o
The implementation supports the _POSIX_V7_LP64_OFF64 programming environment and the application is being built in the _POSIX_V7_LP64_OFF64 programming environment.
o
The implementation supports the _POSIX_V7_LPBIG_OFFBIG programming environment and the application is being built in the _POSIX_V7_LPBIG_OFFBIG programming environment.
[Option End]
All other types of this form are optional.
On est donc bien clairs sur ce points :
(u)int32_t doit être codé sur exactement 32 bits, peu importe l'architecture !!
Voyons en, ensemble, l'implémentation gcc linux :
Citation de: stdint.h de gcc (linux)
#ifndef __int8_t_defined
# define __int8_t_defined
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
#endif
/* Unsigned. */
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
#ifndef __uint32_t_defined
typedef unsigned int uint32_t;
# define __uint32_t_defined
#endif
#if __WORDSIZE == 64
typedef unsigned long int uint64_t;
#else
__extension__
typedef unsigned long long int uint64_t;
#endif
WTF, c'est différent x3
Et là aussi, on définit
(u)int32_t comme un simple
int. Or ce dernier est à taille variable et la spécification ne veut pas que ce soit le cas, alors que croire à la fin ? :blink:
De plus, les
signed ne sont pas au rendez-vous ... Donc ils ne forcent pas la taille des types. Ce sont justes des mots clés inutiles, car par défaut le type est toujours signé, c'est ça ??
Puis bon, pourquoi on n'y définit que
__int8_t_defined et
__uint32_t_defined :ninja: ?
Bon, passons. Je suppose que le fichier est encore différent sous stdint.h de windows ...
Donc bon, un peu la galère pour s'y retrouver ^^
En fait, l'implémentation la plus claire que j'aie pu trouver de stdint.h est
celle-ci.
Sinon, j'ai trouvé d'autres implémentations, comme
celle-ci. Tout est encore différent ...
Heu ... Je nage moi, c'est quoi cette mélasse ? Qui a raison ? Les autres implémentation sont-elles foireuses ? :o
Alors voilà, ce que j'aimerais bien savoir à propos des types ci-dessous, c'est :
- le nombre de bits sur lequel ils sont codés
- par rapport à quelle norme (C89 ou C99)
- sur quels OS
liste :
- int
- signed int
- unsigned int
- short
- signed short
- unisigned short
- short int
- signed short int
- unisigned short int
- long
- signed long
- unsigned long
- long int
- signed long int
- unsigned long int
- long long
- signed long long
- unsigned long long
Je vous remercie pour votre attention et espère que quelqu'un pourra m'indiquer la sortie du tunnel ^_^
Je dois bientôt partir et j'ai pas trop le temps de m'y plonger là, mais pour tenter une première réponse brève:
En C89, la spec de K&R est assez brève et nous dit:
2.2 Data Types and Sizes
There are only a few basic data types in C:
char a single byte, capable of holding one character in the local character set
int an integer, typically reflecting the natural size of integers on the host machine
float single-precision floating point
double double-precision floating point
In addition, there are a number of qualifiers that can be applied to these basic types. short and long apply to integers:
short int sh;
long int counter;
The word int can be omitted in such declarations, and typically it is.
The intent is that short and long should provide different lengths of integers where practical; int will normally be the natural size for a particular machine. short is often 16 bits long, and int either 16 or 32 bits. Each compiler is free to choose appropriate sizes for its own
hardware, subject only to the the restriction that shorts and ints are at least 16 bits, longs are at least 32 bits, and short is no longer than int, which is no longer than long.
The qualifier signed or unsigned may be applied to char or any integer. unsigned numbers are always positive or zero, and obey the laws of arithmetic modulo 2 n, where n is the number of bits in the type. So, for instance, if chars are 8 bits, unsigned char variables have values between 0 and 255, while signed chars have values between -128 and 127 (in a two's complement machine.) Whether plain chars are signed or unsigned is machine-dependent, but printable characters are always positive. The type long double specifies extended-precision floating point. As with integers, the sizes of floating-point objects are implementation-defined; float, double and long double could represent one, two or three distinct sizes. The standard headers <limits.h> and <float.h> contain symbolic constants for all of these sizes, along with other properties of the machine and compiler. These are discussed in Appendix B.
En C-99 c'est une autre histoire; le document qui t'intéresse est la spec ISO-IEC-9899-1999 (http://www.nirvani.net.nyud.net:8090/docs/ansi_c.pdf), qui comporte plus de détails- la page 99 (chapitre 6.7.2) devrait répondre partiellement à tes interrogations (et où on apprend qu'il y'a aussi des types optionnels _Imaginary et _Complex :D ).
Sinon, il faut garder à l'esprit que les compilateurs sont parfois un peu fantaisistes, et que du coup ce qui vaut pour GCC ne vaudra pas forcément ailleurs.
CitationAlors voilà, ce que j'aimerais bien savoir à propos des types ci-dessous, c'est :
- le nombre de bits sur lequel ils sont codés
- par rapport à quelle norme (C89 ou C99)
- sur quels OS
Ça me donnerait bien une petite idée de TP ça...c'est pas dur à tester expérimentalement ce genre de choses :D