Cet article présente une solution mise à jour pour intégrer les types d'entiers standard C99 (stdint.h et inttypes.h) dans des environnements de compilation qui ne les supportent pas nativement, tels que Visual C++ (versions 6 à 2012), Borland C++ Builder (BCB) et GCC. La version 1.01 de cette solution résout les problèmes liés à l'inclusion des fichiers d'en-tête.
Problèmes de chemins d'inclusion et Renommage des fichiers
La version précédente utilisait les noms de fichiers stdint.h et inttypes.h, nécessitant une inclusion via #include "filename.h" pour distinguer les fichiers personnalisés des fichiers système. Cette approche présentait un inconvénient majeur : les fichiers personnalisés ne pouvaient pas être placés dans le répertoire d'inclusion du projet. S'ils y étaient placés, l'inclusion via #include <filename.h> aurait pu privilégier les fichiers du projet, entraînant des références circulaires et empêchant l'utilisation des fichiers système corrects.
Pour pallier ce problème, les fichiers ont été renommés en auto_stdint.h et auto_inttypes.h. Cela permet de les placer dans le répertoire d'inclusion standard du projet sans conflits. L'inconvénient est que l'inclusion se fait maintenant via #include "auto_stdint.h" et #include "auto_inttypes.h".
Les macros de préprocesseur ont également été renommées pour refléter ce changement :
__AUTO_STDINT_H_INCLUDED(anciennement_STDINT_H_ALL_)__AUTO_STDINT_H_USESYS(anciennement_STDINT_H_SYS_)__AUTO_INTTYPES_H_INCLUDED(anciennement_INTTYPES_H_ALL_)__AUTO_INTTYPES_H_USESYS(anciennement_INTTYPES_H_SYS_)
Compatibilité avec les compilateurs
La compatibilité a été testée et vérifiée pour plusieurs versions de compilateurs :
- Visual C++ 2008 : Ne supporte pas
stdint.hniinttypes.h. - Visual C++ 2012 : Spuporte
stdint.hmais pasinttypes.h.
Les autres compilateurs testés incluent BCB6, GCC (Linux, Mac OS X, MinGW) qui supportent nativement ces standards.
Fichiers inclus dans la solution
La distribution de cette solution comprend les fichiers suivants :
auto_stdint.h: Implémentation personnalisée destdint.h.auto_inttypes.h: Implémentation personnalisée deinttypes.h.c99int.c: Un fichier source d'exemple pour tester les types C99.- Divers fichiers de projet pour Visual Studio (
.sln,.vcproj,.vcxproj) et Borland C++ Builder (.bpf,.bpr). - Un
makefilepour la compilation avec GCC.
Contenu des fichiers d'en-tête personnalisés
auto_stdint.h
Ce fichier fournit les définitions standard pour les types entiers de largeur fixe, de largeur minimale, de largeur la plus rapide, ainsi que les types capables de contenir des pointeurs d'objets et les types de plus grande largeur. Il inclut également les macros correspondantes pour les limites de ces types.
Les directives de préprocesseur déterminent si le compilateur dispose déjà d'une implémentation de stdint.h. Si c'est le cas (par exemple, avec GCC ou des versions récentes de MSVC), le fichier système est inclus. Sinon, l'implémentation personnalisée est utilisée.
////////////////////////////////////////////////////////////
/*
auto_stdint.h: Compatible C99 stdint.h
Author: zyl910
Version: V1.01
Update: 2013-01-10
*/
////////////////////////////////////////////////////////////
#ifndef __AUTO_STDINT_H_INCLUDED
#define __AUTO_STDINT_H_INCLUDED
#undef __AUTO_STDINT_H_USESYS
#if defined(__GNUC__)
#define __AUTO_STDINT_H_USESYS
#elif defined(_MSC_VER) && _MSC_VER >= 1600 // VC2010 and later
#define __AUTO_STDINT_H_USESYS
#elif defined(__BORLANDC__) && __BORLANDC__ >= 0x0560 // BCB6
#define __AUTO_STDINT_H_USESYS
#endif
#ifdef __AUTO_STDINT_H_USESYS
#include <stdint.h>
#else
#include <limits.h>
#include <wchar.h> // For WCHAR_MIN/MAX definitions
#ifndef _MSC_STDINT_H_
#define _MSC_STDINT_H_
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
#ifdef _WIN64
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
// Limits definitions
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
// ... (other limit definitions) ...
#define UINTMAX_MAX UINT64_MAX
#define PTRDIFF_MIN INT32_MIN // Adjust for 64-bit
#define PTRDIFF_MAX INT32_MAX // Adjust for 64-bit
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX
#define SIZE_MAX UINT32_MAX // Adjust for 64-bit
#endif
#ifndef WCHAR_MIN
#define WCHAR_MIN 0
#endif
#ifndef WCHAR_MAX
#define WCHAR_MAX _UI16_MAX
#endif
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
// Constant macros definitions
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif
#endif // _MSC_STDINT_H_
#endif // __AUTO_STDINT_H_USESYS
#endif // __AUTO_STDINT_H_INCLUDED
</wchar.h></limits.h></stdint.h>
auto_inttypes.h
Ce fichier fournit les macros de spécification de format pour printf et scanf, ainsi que les fonctions utilitaires pour les types d'entiers de plus grande largeur, telles que imaxabs, imaxdiv, strtoimax et wcstoimax.
Comme pour auto_stdint.h, il vérifie d'abord si le compilateur fournit nativement inttypes.h. Sinon, il utilise une implémentation personnalisée.
////////////////////////////////////////////////////////////
/*
auto_inttypes.h: Compatible C99 inttypes.h
Author: zyl910
Version: V1.01
Update: 2013-01-10
*/
////////////////////////////////////////////////////////////
#ifndef __AUTO_INTTYPES_H_INCLUDED
#define __AUTO_INTTYPES_H_INCLUDED
#undef __AUTO_INTTYPES_H_USESYS
#if defined(__GNUC__)
#define __AUTO_INTTYPES_H_USESYS
#elif defined(_MSC_VER) // VC2012 does not support inttypes.h
#elif defined(__BORLANDC__) // BCB6 does not support inttypes.h
#else
#define __AUTO_INTTYPES_H_USESYS // Assume other compilers support C99
#endif
#ifdef __AUTO_INTTYPES_H_USESYS
#include <inttypes.h>
#else
#include "auto_stdint.h" // Include our custom stdint.h
#ifndef _MSC_INTTYPES_H_
#define _MSC_INTTYPES_H_
// Format specifier macros
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
// Signed integers
#define PRId8 "d"
#define PRIi8 "i"
// ... (other PRI macros for various widths) ...
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIdMAX "I64d"
#define PRIiMAX "I64i"
#define PRIdPTR "Id"
#define PRIiPTR "Ii"
// Unsigned integers
#define PRIo8 "o"
#define PRIu8 "u"
// ... (other PRI macros for various widths) ...
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIoMAX "I64o"
#define PRIuMAX "I64u"
#define PRIoPTR "Io"
#define PRIuPTR "Iu"
// Scanf format specifier macros
#define SCNd8 "d"
#define SCNi8 "i"
// ... (other SCN macros for various widths) ...
#define SCNd64 "I64d"
#define SCNi64 "I64i"
#define SCNdMAX "I64d"
#define SCNiMAX "I64i"
#ifdef _WIN64
# define SCNdPTR "I64d"
# define SCNiPTR "I64i"
#else
# define SCNdPTR "ld"
# define SCNiPTR "li"
#endif
// ... (SCN macros for unsigned integers) ...
#endif // __STDC_FORMAT_MACROS
// Functions for greatest-width integer types
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
#define imaxabs _abs64 // For MSVC
// imaxdiv function implementation for MSVC
#ifdef _MSC_VER
// ... (imaxdiv implementation) ...
#endif
#define strtoimax _strtoi64 // For MSVC
#define strtoumax _strtoui64 // For MSVC
#define wcstoimax _wcstoi64 // For MSVC
#define wcstoumax _wcstoui64 // For MSVC
#endif // _MSC_INTTYPES_H_
#endif // __AUTO_INTTYPES_H_USESYS
#endif // __AUTO_INTTYPES_H_INCLUDED
Exemple de compilation et de test
Le fichier c99int.c contient un exemple simple qui utilise ces types et macros pour afficher des valeurs. Le makefile fourni permet de compiler ce code avec GCC.
Les tests de compilation ont été effectués avec succès sur une variété de compilateurs et d'architectures, y compris différentes versions de Visual Studio (32 bits et 64 bits), BCB6, et GCC.
La solution garantit la compatibilité avec les types d'entiers C99, améliorant ainsi la portabilité du code C entre différents compilateurs.