Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

int32_t (et autres) portables ?

13 réponses
Avatar
PIGUET Bruno
Bonjour,

Désolé si c'est une FAQ.

J'ai besoin de déclarer, pour de la lecture de fichier binaires,
des types entiers dont je connais exactement le nombre de bits et le
caractère signé/non_signé.
En C99, #include <stdint.h> et déclaration du genre "int16_t
x1=-16;", et c'est réglé.
Avec certains vieux compilateurs (HP-UX pour ne pas le nommer),
c'était plutôt :
#include <stdlib.h> et déclaration du genre "int32_t x2=-32;", et
stdint.h n'existe pas.

Est-ce que les vieux routard du groupe auraient une solution, c'est
à dire une syntaxe qui marche dans les 2 cas ? (autre que créer moi-même
un stdint.h "kivabien" sur les machines où il n'existe pas)

Merci,

Bruno.

10 réponses

1 2
Avatar
espie
In article <f3moiq$40f$,
PIGUET Bruno wrote:
Bonjour,

Désolé si c'est une FAQ.

J'ai besoin de déclarer, pour de la lecture de fichier binaires,
des types entiers dont je connais exactement le nombre de bits et le
caractère signé/non_signé.
En C99, #include <stdint.h> et déclaration du genre "int16_t
x1=-16;", et c'est réglé.
Avec certains vieux compilateurs (HP-UX pour ne pas le nommer),
c'était plutôt :
#include <stdlib.h> et déclaration du genre "int32_t x2=-32;", et
stdint.h n'existe pas.

Est-ce que les vieux routard du groupe auraient une solution, c'est
à dire une syntaxe qui marche dans les 2 cas ? (autre que créer moi-même
un stdint.h "kivabien" sur les machines où il n'existe pas)


Non, il n'y a pas. Pas de facon portable en tout cas.

Le plus gros interet de stdint.h, de ce point de vue, c'est de donner
des noms `uniques' a des machins qui existaient souvent sous forme
de typedef, de #define et autres joyeusetes, de facon pas du tout
compatible d'une machine a une autre...

Avatar
PIGUET Bruno
Marc Espie wrote:

Non, il n'y a pas. Pas de facon portable en tout cas.

Donc je suis tombé dans les #if defined, finalement assez simples

dans mon cas (testé uniquement sur les quelques machines auxquelles j'ai
accès) :

#ifdef C99
#include <stdint.h>
#else
#if defined(WIN32) || defined(OS2)
typedef int int32_t;
typedef unsigned int uint32_t;
#else
/* inttypes.h fournit les dfinitions attendues sur HP-UX et gcc.
* Internet semble dire que c'est OK aussi pour AIX, sun, osf, et IRIX.
* pour les BSD, il semblerait que ce soit <sys/types.h> */
#include <inttypes.h>
#endif
#endif

Bruno.

Avatar
Vincent Lefevre
Dans l'article <f3onte$pre$,
PIGUET Bruno écrit:

Marc Espie wrote:
Non, il n'y a pas. Pas de facon portable en tout cas.

Donc je suis tombé dans les #if defined, finalement assez simples

dans mon cas (testé uniquement sur les quelques machines auxquelles j'ai
accès) :

#ifdef C99


#if __STDC__ == 1 && __STDC_VERSION__ >= 199901

#include <stdint.h>
#else
#if defined(WIN32) || defined(OS2)
typedef int int32_t;
typedef unsigned int uint32_t;
#else
/* inttypes.h fournit les dfinitions attendues sur HP-UX et gcc.
* Internet semble dire que c'est OK aussi pour AIX, sun, osf, et IRIX.
* pour les BSD, il semblerait que ce soit <sys/types.h> */
#include <inttypes.h>
#endif
#endif


Mieux vaut peut-être définir un my_int32_t (avec les typedef qu'il
faut suivant le contexte), car certains en-têtes liés à la plateforme
peuvent définir int32_t. Si je me souviens bien, c'était le cas sous
Solaris avec juste un #include <unistd.h>. Imagine qu'on ait le même
genre de problème sous Windows ou OS/2...

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Pierre Maurette
Marc Espie wrote:

Non, il n'y a pas. Pas de facon portable en tout cas.

Donc je suis tombé dans les #if defined, finalement assez simples dans

mon cas (testé uniquement sur les quelques machines auxquelles j'ai accès) :

#ifdef C99
#include <stdint.h>
#else
#if defined(WIN32) || defined(OS2)
typedef int int32_t;
typedef unsigned int uint32_t;
#else
/* inttypes.h fournit les dfinitions attendues sur HP-UX et gcc.
* Internet semble dire que c'est OK aussi pour AIX, sun, osf, et IRIX.
* pour les BSD, il semblerait que ce soit <sys/types.h> */
#include <inttypes.h>
#endif
#endif


En C99, les types intN_t et uintN_t garantissent un nombre exact de
bits sans padding et pour les signés une représentation en complément à
2. En vertu de quoi, ces types sont optionnels, c'est à dire qu'ils ne
seront pas implémentés si la plateforme ne le possède pas en natif. La
norme précise que les types seront (il me semble que c'est un "shall"
cher à la norme) implémentés - typedef-ed - dans le cas contraire.
Le choix est fait pour chaque paire signé - non signé, les deux types
doivent être implémentés, ou aucun.

Le préprocesseur n'a pas accès à sizeof, mais vous pouvez inclure
limits.h. Vous pouvez peut-être vous en sortir au plus près de la norme
C99 avec un truc comme:
#include <limits.h>
#if CHAR_MAX == 2147483647 && CHAR_MIN == -2147483648 && UCHAR_MAX ==
4294967295
/* faire les typedef */
#elif SHRT_MAX == 2147483647 && SHRT_MIN == -2147483648 && USHRT_MAX ==
4294967295
/* faire les typedef */
#elif INT_MAX == 2147483647 && INT_MIN == -2147483648 && UINT_MAX ==
4294967295
/* faire les typedef */
#elif LONG_MAX == 2147483647 && LONG_MIN == -2147483648 && ULONG_MAX ==
4294967295
/* faire les typedef */
#else
#error Aucun type ne correspond à int32_t / uint32_t
#endif

Au cas où vous auriez un XXX_MAX de 2147483647 et un XXX_MIN de
-2147483647 vous laisserez penser à une implémentation particulière des
signés (signe + mantisse), et vous prendriez alors une décision.

--
Pierre Maurette


Avatar
espie
In article <20070601103054$,
Vincent Lefevre <vincent+ wrote:
Dans l'article <f3onte$pre$,
PIGUET Bruno écrit:

Marc Espie wrote:
Non, il n'y a pas. Pas de facon portable en tout cas.

Donc je suis tombé dans les #if defined, finalement assez simples

dans mon cas (testé uniquement sur les quelques machines auxquelles j'ai
accès) :

#ifdef C99


#if __STDC__ == 1 && __STDC_VERSION__ >= 199901

#include <stdint.h>
#else
#if defined(WIN32) || defined(OS2)
typedef int int32_t;
typedef unsigned int uint32_t;
#else
/* inttypes.h fournit les dfinitions attendues sur HP-UX et gcc.
* Internet semble dire que c'est OK aussi pour AIX, sun, osf, et IRIX.
* pour les BSD, il semblerait que ce soit <sys/types.h> */
#include <inttypes.h>
#endif
#endif


Mieux vaut peut-être définir un my_int32_t (avec les typedef qu'il
faut suivant le contexte), car certains en-têtes liés à la plateforme
peuvent définir int32_t. Si je me souviens bien, c'était le cas sous
Solaris avec juste un #include <unistd.h>. Imagine qu'on ait le même
genre de problème sous Windows ou OS/2...


Mieux vaut donner un autre nom a son typedef dans ce cas.
Je te rappelle que tous les noms en *_t sont reserves pour l'implementation.

A la limite, int32_myt serait plus portable. ;-)



Avatar
espie
In article ,
Pierre Maurette wrote:
Marc Espie wrote:

Non, il n'y a pas. Pas de facon portable en tout cas.

Donc je suis tombé dans les #if defined, finalement assez simples dans

mon cas (testé uniquement sur les quelques machines auxquelles j'ai accès) :

#ifdef C99
#include <stdint.h>
#else
#if defined(WIN32) || defined(OS2)
typedef int int32_t;
typedef unsigned int uint32_t;
#else
/* inttypes.h fournit les dfinitions attendues sur HP-UX et gcc.
* Internet semble dire que c'est OK aussi pour AIX, sun, osf, et IRIX.
* pour les BSD, il semblerait que ce soit <sys/types.h> */
#include <inttypes.h>
#endif
#endif


En C99, les types intN_t et uintN_t garantissent un nombre exact de
bits sans padding et pour les signés une représentation en complément à
2. En vertu de quoi, ces types sont optionnels, c'est à dire qu'ils ne
seront pas implémentés si la plateforme ne le possède pas en natif. La
norme précise que les types seront (il me semble que c'est un "shall"
cher à la norme) implémentés - typedef-ed - dans le cas contraire.
Le choix est fait pour chaque paire signé - non signé, les deux types
doivent être implémentés, ou aucun.


Si on veut un type d'exactement la bonne taille, c'est effectivement un
probleme. stdint.h prevoit INT32_MIN pour verifier l'existence du type.

Si on veut des types d'au moins une certaine taille, il vaut mieux
utiliser int_least32_t et consorts. Ceux-la sont obligatoire vis-a-vis
de la norme.

Le préprocesseur n'a pas accès à sizeof, mais vous pouvez inclure
limits.h. Vous pouvez peut-être vous en sortir au plus près de la norme
C99 avec un truc comme:
#include <limits.h>
#if CHAR_MAX == 2147483647 && CHAR_MIN == -2147483648 && UCHAR_MAX ==
4294967295
/* faire les typedef */
#elif SHRT_MAX == 2147483647 && SHRT_MIN == -2147483648 && USHRT_MAX ==
4294967295
/* faire les typedef */
#elif INT_MAX == 2147483647 && INT_MIN == -2147483648 && UINT_MAX ==
4294967295
/* faire les typedef */
#elif LONG_MAX == 2147483647 && LONG_MIN == -2147483648 && ULONG_MAX ==
4294967295
/* faire les typedef */
#else
#error Aucun type ne correspond à int32_t / uint32_t
#endif


C'est pour du pre-C99, je suppose ?



Avatar
Pierre Maurette

[...]

Si on veut un type d'exactement la bonne taille, c'est effectivement un
probleme. stdint.h prevoit INT32_MIN pour verifier l'existence du type.


Le problème dépasse celui de la taille. A partir du moment où l'on
asserte (franglais ?) que l'on dispose de int32_t, on peut faire des
hypothèses sûres que l'on ne peut pas faire autrement. Manque quand
même le boutisme, qui rest indéterminé à priori.

Si on veut des types d'au moins une certaine taille, il vaut mieux
utiliser int_least32_t et consorts. Ceux-la sont obligatoire vis-a-vis
de la norme.


J'ai eu récemment un doute. Sur un truc appelé éventuellement à être
optimisé en final, j'avais besoin d'un type contenant une somme de
quelques dizaines de uint8_t. J'ai donc choisi (via un typedef, pour
pouvoir tester) un uint_fast16_t, démarche logique aujourd'hui. J'étais
avec un gcc assez vieux sous Windows, cible 32bit. J'ai regardé le
sizeof, je m'attendais à 4, j'ai lu 2. J'ai changé pour un unsigned,
démarche logique hier. Pour des boucles de calculs sur entiers, il
aurait fallu l'intervention de l'arbitre vidéo pour départager. Mais à
partir du moment où j'avais une conversion en double à un niveau
intermédiaire de la boucle, l'avantage à l'int était flagrant. De
l'ordre de 400 -> 300 en unités quelconques de temps. Il se trouve que
c'est une boucle assez stratégique dans l'appli, ça m'inquiète. Sans
plus puisque ça doit se compiler avec un gcc récent et le -march qui va
bien, ou alors Icc 8.1.

Le préprocesseur n'a pas accès à sizeof, mais vous pouvez inclure
limits.h. Vous pouvez peut-être vous en sortir au plus près de la norme
C99 avec un truc comme:
#include <limits.h>
#if CHAR_MAX == 2147483647 && CHAR_MIN == -2147483648 && UCHAR_MAX ==
4294967295
/* faire les typedef */
#elif SHRT_MAX == 2147483647 && SHRT_MIN == -2147483648 && USHRT_MAX ==
4294967295
/* faire les typedef */
#elif INT_MAX == 2147483647 && INT_MIN == -2147483648 && UINT_MAX ==
4294967295
/* faire les typedef */
#elif LONG_MAX == 2147483647 && LONG_MIN == -2147483648 && ULONG_MAX ==
4294967295
/* faire les typedef */
#else
#error Aucun type ne correspond à int32_t / uint32_t
#endif


C'est pour du pre-C99, je suppose ?


C'était pour Bruno et son HP-UX.
J'admets d'ailleurs que la certitude de trouver un type natif de 32
bits sans padding avec complément à deux n'est peut-être pas garantie
par rapport à la norme avec mes tests. Mais sur les archi que je
connais personnellement, et celles dont je connais l'existence par
fr.comp.lang.c, ça fonctionne.
Sinon, il y a une grosse connerie qui m'échappe ?

--
Pierre Maurette


Avatar
Antoine Leca
En news:20070601103054$,
Vincent Lefevre va escriure:
#ifdef C99


#if __STDC__ == 1 && __STDC_VERSION__ >= 199901


Techniquement oui, mais

#if __STDC_VERSION__-0 >= 199901

va te permettre de choper plus de cas positifs (comme ceux où le compilo
fournit un support C99, mais où la compatibilité stricte avec la norme est
désactivée).

Le "-0" est là pour ne pas fâcher les vieux préprocesseurs (ne respectant
pas la norme) qui remplacent un identificateur absent par rien (plutôt que
par 0); c'est une bonne précaution à prendre même derrière __STDC__ == 1 ...


#include <stdint.h>



Je rajouterais bien un truc comme

#elif _XOPEN_SOURCE-0 >= 4
#include <inttypes.h>

(cf. google ou fr.comp.os.unix pour la « bonne » valeur de la contante)

#else




Antoine


Avatar
espie
In article ,
Pierre Maurette wrote:

[...]

Si on veut un type d'exactement la bonne taille, c'est effectivement un
probleme. stdint.h prevoit INT32_MIN pour verifier l'existence du type.


Le problème dépasse celui de la taille. A partir du moment où l'on
asserte (franglais ?) que l'on dispose de int32_t, on peut faire des
hypothèses sûres que l'on ne peut pas faire autrement. Manque quand
même le boutisme, qui rest indéterminé à priori.

Si on veut des types d'au moins une certaine taille, il vaut mieux
utiliser int_least32_t et consorts. Ceux-la sont obligatoire vis-a-vis
de la norme.


J'ai eu récemment un doute. Sur un truc appelé éventuellement à être
optimisé en final, j'avais besoin d'un type contenant une somme de
quelques dizaines de uint8_t. J'ai donc choisi (via un typedef, pour
pouvoir tester) un uint_fast16_t, démarche logique aujourd'hui. J'étais
avec un gcc assez vieux sous Windows, cible 32bit. J'ai regardé le
sizeof, je m'attendais à 4, j'ai lu 2. J'ai changé pour un unsigned,
démarche logique hier. Pour des boucles de calculs sur entiers, il
aurait fallu l'intervention de l'arbitre vidéo pour départager. Mais à
partir du moment où j'avais une conversion en double à un niveau
intermédiaire de la boucle, l'avantage à l'int était flagrant. De
l'ordre de 400 -> 300 en unités quelconques de temps. Il se trouve que
c'est une boucle assez stratégique dans l'appli, ça m'inquiète. Sans
plus puisque ça doit se compiler avec un gcc récent et le -march qui va
bien, ou alors Icc 8.1.


Ca ressemble fort a une erreur de configuration du compilo ou du systeme.
Effectivement, si c'est plus rapide en 32 bits, la definition du
uint_fast16_t est fausse. Si je regarde l'OS que j'ai sous la main, sur
une archi i386, tous les int_fastN_t sont definis comme equivalents
a des int32_t (sauf int_fast64_t, bien sur).


C'était pour Bruno et son HP-UX.
J'admets d'ailleurs que la certitude de trouver un type natif de 32
bits sans padding avec complément à deux n'est peut-être pas garantie
par rapport à la norme avec mes tests. Mais sur les archi que je
connais personnellement, et celles dont je connais l'existence par
fr.comp.lang.c, ça fonctionne.


Ben non, elle n'est effectivement pas garantie. Il existe effectivement
des archis exotiques, plutot du cote des DSP, qui ne gerent en natif que
des valeurs 64 bits.


Avatar
Pierre Maurette

[...]

Ben non, elle n'est effectivement pas garantie. Il existe effectivement
des archis exotiques, plutot du cote des DSP, qui ne gerent en natif que
des valeurs 64 bits.


Dans ce cas, mon bordel fonctionne, puisque ça bloque à la compilation
avec un message "Aucun type ne correspond à int32_t / uint32_t" et
comme je l'écrivais "vous prendriez alors une décision".

J'ajoute quand même les DSP 64 bits à la liste de archis qui existent
mais que je ne connais que par fr.comp.lang.c ;-)

Ce que je voulais dire, c'est que je ne suis pas absolument absolument
absolument absolument convaincu (encore que le contre-exemple
m'échappe) qu'une réponse:
TYPE_MAX = 2147483647
TYPE_MIN = -2147483648
et [même si je pense que ça redonde]:
UTYPE_MAX = 4294967295

signifie obligatoirement TYPE est 32 bits sans padding, signés en
complément à 2.

En fait, si, j'en suis convaincu ... [Poil au nez]

--
Pierre Maurette

1 2