Malcolm McLean said:
size_t and ssize_t may be acceptable here.
Maximum object size almost always equals 2^width of address bus =
processing
register width. Not always of course. It depends if it has to work
absolutely
everywhere. But there's no totally portable solution, because C can't
guarantee
that "a 64 bit machine" actually means anything on some architecture
someone
could invent.
Yes, I could use int for the shorter (16 32 32) variant and ssize_t for the
longer (16 32 64) at least with the compilers I am using at the moment.
However, I have an almost instinctive distrust that such names can be relied
on to do the expected thing on all compilers. I've had a number of occasions
where something that worked well on one compiler failed to do what I wanted
on another. And such differences may not be picked up at compile time. That
kind of bug can be hard to find.
So I currently define all the types I need explicitly and avoid names that
compilers might use. If you don't mind or are interested I'll post the full
setup below. Maybe someone has suggestions to improve this. At least it will
explain the bigger picture. Asbestos pants on!
For x86 there are four directories as follows
src/comn
src/x86_16
src/x86_32
src/x86_64
Each of the x86_NN directories has a file called os_bits_log2.h. Aside from
#ifdefs etc and comments those three files have exactly one line. Their
contents are, respectively, nothing more than
#define OS_BITS_LOG2 4
#define OS_BITS_LOG2 5
#define OS_BITS_LOG2 6
These are saying that for a 16-bit target the log2 of the number of bits is
4 and 2 ** 4 is 16 and similar for the other widths.
The common directory (src/comn) includes a file called os_bits.h which is as
follows:
#ifndef OS_BITS_H
#define OS_BITS_H
#include "os_bits_log2.h"
#define OS_BITS (1 << OS_BITS_LOG2) /* 16, 32 or 64 */
#define OS_BYTES (OS_BITS >> 3) /* 2, 4 or 8 */
#endif
A build of a 16-bit system will set the include directories up in this
order: first, src/x86_16, second src/comn. Similar for 32-bit and 64-bit
builds. A makefile matches compiler, switches and include paths.
Still with me?
The above sets up OS_BITS. That is used toward the end of the main types
header which is called os_types.h. Its current incarnation is below. As I
say, I would welcome an expert view of this. Even if there are no comments
this does serve to illustrate the approach I am currently taking. I may
change it. This is fairly new stuff to me but so far it seems to work well.
James
#ifndef OS_TYPES_H
#define OS_TYPES_H
#include "os_bits.h"
#include <limits.h>
/* We need to define
si8 and ui8
si16 and ui16
si32 and ui32
si64 and ui64
si_small and ui_small (32-bit on 64-bit machines)
si_large and ui_large (64-bit on 64-bit machines)
*/
/*
* Define 8-bit integers
*/
#if SCHAR_MAX == 0x7f
typedef signed char si8;
typedef unsigned char ui8;
#define si8_FMT_DEC "i"
#define ui8_FMT_DEC "u"
#else
#error "No type candidate for si8 and ui8"
#endif
/*
* 16-bit integers
*/
#if INT_MAX == 0x7fff
typedef signed int si16;
typedef unsigned int ui16;
#define si16_FMT_DEC "i"
#define ui16_FMT_DEC "u"
#elif SHRT_MAX == 0x7fff
typedef signed short si16;
typedef unsigned short ui16;
#define si16_FMT_DEC "i"
#define ui16_FMT_DEC "u"
#else
#error "No type candidate for si16 and ui16"
#endif
/*
* 32-bit integers
*/
/* Using small shifts to stop Open Watcom compiler warning */
#if (INT_MAX >> 8 >> 8) == 0x7fff
typedef signed int si32;
typedef unsigned int ui32;
#define si32_FMT_DEC "i"
#define ui32_FMT_DEC "u"
#elif (LONG_MAX >> 16) == 0x7fff
typedef signed long si32;
typedef unsigned long ui32;
#define si32_FMT_DEC "li"
#define ui32_FMT_DEC "lu"
#else
#error "No type candidate for si32 and ui32"
#endif
/*
* 64-bit integers
*/
/* Using small shifts to stop Open Watcom compiler warning */
#if (INT_MAX >> 8 >> 8 >> 8 >> 8 >> 8 >> 8) == 0x7fff
typedef signed int si64;
typedef unsigned int ui64;
#define si64_FMT_DEC "i"
#define ui64_FMT_DEC "u"
#elif (((LONG_MAX >> 16) >> 16) >> 16) == 0x7fff
typedef signed long si64;
typedef unsigned long ui64;
#define si64_FMT_DEC "li"
#define ui64_FMT_DEC "lu"
#elif (((LLONG_MAX >> 16) >> 16) >> 16) == 0x7fff
typedef signed long long si64;
typedef unsigned long long ui64;
#define si64_FMT_DEC "lli"
#define ui64_FMT_DEC "llu"
#else
typedef struct {ui32 low; si32 high;} si64; /* Limited use */
typedef struct {ui32 low; ui32 high;} ui64; /* Limited use */
/* #warning "Using structures for si64 and ui64" */
#define si64_FMT_DEC "%(unprintable %x)"
#define ui64_FMT_DEC "%(unprintable %x)"
#endif
/*
* Define the potential number of digits when printed
*/
#define si8_DIG_DEC 3
#define ui8_DIG_DEC 3
#define si16_DIG_DEC 5
#define ui16_DIG_DEC 5
#define si32_DIG_DEC 10
#define ui32_DIG_DEC 10
#define si64_DIG_DEC 19
#define ui64_DIG_DEC 20
/*
* Define small and large integer types. These are normally the same but
* on at least x86_64 the small integers are half the normal width. Use
* large ints by default. Use small ones only where it is known that
* large ints are unnecessary.
*/
#if OS_BITS == 16
typedef si16 si_small;
typedef ui16 ui_small;
#define si_small_MAX 0x7fff
#define ui_small_MAX 0xffffU
#define si_small_DIG_DEC si16_DIG_DEC
#define ui_small_DIG_DEC ui16_DIG_DEC
#define si_small_FMT_DEC si16_FMT_DEC
#define ui_small_FMT_DEC ui16_FMT_DEC
typedef si16 si_large;
typedef ui16 ui_large;
#define si_large_MAX 0x7fff
#define ui_large_MAX 0xffffU
#define si_large_DIG_DEC si16_DIG_DEC
#define ui_large_DIG_DEC ui16_DIG_DEC
#define si_large_FMT_DEC si16_FMT_DEC
#define ui_large_FMT_DEC ui16_FMT_DEC
#elif OS_BITS == 32
typedef si32 si_small;
typedef ui32 ui_small;
#define si_small_MAX (0x7fffffff)
#define ui_small_MAX (0xffffffffU)
#define si_small_DIG_DEC si32_DIG_DEC
#define ui_small_DIG_DEC ui32_DIG_DEC
#define si_small_FMT_DEC si32_FMT_DEC
#define ui_small_FMT_DEC ui32_FMT_DEC
typedef si32 si_large;
typedef ui32 ui_large;
#define si_large_MAX (0x7fffffff)
#define ui_large_MAX (0xffffffffU)
#define si_large_DIG_DEC si32_DIG_DEC
#define ui_large_DIG_DEC ui32_DIG_DEC
#define si_large_FMT_DEC si32_FMT_DEC
#define ui_large_FMT_DEC ui32_FMT_DEC
#elif OS_BITS == 64
typedef si32 si_small;
typedef ui32 ui_small;
#define si_small_MAX (0x7fffffff)
#define ui_small_MAX (0xffffffffU)
#define si_small_DIG_DEC si32_DIG_DEC
#define ui_small_DIG_DEC ui32_DIG_DEC
#define si_small_FMT_DEC si32_FMT_DEC
#define ui_small_FMT_DEC ui32_FMT_DEC
typedef si64 si_large;
typedef ui64 ui_large;
#define si_large_MAX (0x7fffffffffffffff)
#define ui_large_MAX (0xffffffffffffffffU)
#define si_large_DIG_DEC si64_DIG_DEC
#define ui_large_DIG_DEC ui64_DIG_DEC
#define si_large_FMT_DEC si64_FMT_DEC
#define ui_large_FMT_DEC ui64_FMT_DEC
#else
#error "OS bit width not correctly specified"
#endif
/*
* Time stamp counter type
*/
typedef ui64 tsc64;
typedef ui32 tsc32;
#endif