Portable 64 bit integer type

Here I would like to write about coding a “portable” C programs in a sense that they produce same results when compiled and executed on 32 and 64 bits architectures.

The problem I faced with DES is that I need to make sure that my integers are exactly 32 bits on all platforms where I compile it. Also I must be able to create long integers which are exactly 64 bits wide.

What makes C code different on 64 bits platforms.

First thing which comes to mind is the size of integer data types on 32 bits and 64 bit platforms.
Using the common sense we expect 32 bits platforms to have (ILP32 model):

  • 4 bytes per pointer
  • 4 bytes per int
  • 4 bytes per long

and perhaps we expect that 64 bits platforms have:

  • 8 bytes per pointer
  • 4 bytes per int (or 8?)
  • 8 bytes per long

The problem is that you cannot be sure about these values.
The figures above for 64 bit platform are called LP64 (“Longs and Pointers are 64 bits: LP64″) data model.
In fact, there are different data models which denote various schemes.


size of integer data models LLP64 ILP64

Standard (C99) defines minimum size requirements (in number of bytes) for the int and long types.
It also says that long type should be at least as big as, int but they can have equal sizes.
However, when we port some code to a new platform, it is usually easy to find out the data model.

The following small test will show the sizes of main data types.

#include <stdio.h>

int main(int argc, char * argv[])
{

printf("sizeof(void*) = %d bytes\n", sizeof(void*));
printf("sizeof(char) = %d byte\n", sizeof(char));
printf("sizeof(short) = %d bytes\n", sizeof(short));
printf("sizeof(int) = %d bytes\n", sizeof(int));
printf("sizeof(long) = %d bytes\n", sizeof(long));
printf("sizeof(long int) = %d bytes\n", sizeof(long int));
printf("sizeof(float) = %d bytes\n", sizeof(float));
printf("sizeof(double) = %d bytes\n", sizeof(double));

//the next line can fail on some old compilers
printf("sizeof(long long) = %d bytes\n", sizeof(long long));

//this works only on C++ compilers
printf("sizeof(bool) = %d bytes\n", sizeof(bool));

return 0;
}

Some platforms (like HP/UX with LP64 and ILP32) support several models and you can change them by specifying proper compiler time flags and runtime libraries.

Is there a portable way to have 32 bits integers in C?

So we are interested in writing such code which will use exact 64 bit integer type on platforms where it is available. I would like to mention here that you can always do the proper stuff in *runtime* just by using sizeof() operator.

What is more tricky is the *compile time* solution.

If we speak about C++, the solution is also easy to implement with templates, see the section below.
Sometimes, compiler predefines a special macro to make life easier:


//this works on some systems:
#if __LP64__
typedef long I32;
#endif

However, you cannot be sure about all platforms.

A standard compliant way

The good news is that C99 standard for C language introduces some very handy headers:

#include <inttypes.h>
#include <stdint.h>

which allow you to use the following integer types with fixed size:

  • int8_t
  • int16_t
  • int32_t
  • int64_t

When “stdint.h” is available it is best solution since int32_t is guaranteed to be always 32 bits wide on all data models (platforms).

The problem is that some compilers do not support stdint.h header (after all, your compiler must be C99 compliant for this feature). For example, Microsoft Visual C compilers (I tried 2003 and 2008 versions) do not come with these headers. Unlike Micrisoft, most common versions of gcc support these headers.

In order to fix this Microsoft specific problem, one can use something like this:

#ifdef _MSC_VER
#include "ms_inttypes.h"
#include "ms_stdint.h"
#else
#include <inttypes.h>
#include <stdint.h>
#endif

Alexander Chemeris has made special versions of inttypes.h and stdint.h which work on Microsoft compilers.

One can download these headers, than rename it, adding prefix “ms_” to avoid conflicts on platforms with built-in support.

If your compiler does not support stdint.h you can also try to use pstdint.h header made by Paul Hsieh.

I would also suggest checking the stdint.h wikipedia page for some updates which may happen on this topic.

Lucky C++

More than ten years ago, Kevin S. Van Horn has published an article Compile-time Assertions in C++.

We can use this idea to assert the size of integer type:


template <bool t>
struct ctassert {
enum { N = 1 - 2 * int(!t) };
static char A[N];
};
template <bool t>
char ctassert<t>::A[N];

static ctassert<sizeof(int) == 4> TEST_INT_4_BYTES_LONG;
static ctassert<sizeof(long) == 8> TEST_LONG_8_BYTES_LONG;

The code above will fail to compile with weird messages about subscripts of A[N] array. Note, “static” is used here to make sure that assertions are not removed by optimizing compiler.

Boost your code

BOOST library does not provide you a special way to use integers with exact number of bytes.
However, there are other two very nice features if you consider using boost/cstdint.hpp header.

The following integer types are introduced in boost namespace:

  • Integer types with at least N bits requirement. This is a lower bound guarantee for the size of the integer value.
  • Fastest integer types with at least N bits requirement. The code tries to use platform specific features to make sure that N bits integer is represented in most optimal way.

So thats it.

It looks like until C99 standard is implemented in most compilers we do not have “portable” way to define integers with exact size. However, there are some tricks to make sure that code will either work or fail to compile.

Leave a Reply