views:

342

answers:

8

I think I know what #ifdefs I need to use to be x86-32 and x86-64 compatible on both msvc and gcc, see below. Is this complete for those platforms?

#if defined(_MSC_VER)
#  if defined(_M_IA64) || defined(_M_X64)
#    define SIZEOF_SIZE_T 8
#    define SIZEOF_VOIDP  8
#  elif defined(_M_IX86)
#    define SIZEOF_SIZE_T 4
#    define SIZEOF_VOIDP  4
#  else
#    error "Unsupported MSVC platform"
#  endif
#elif defined(__GNUG__)
#  if defined(__x86_64__) || defined(__ia64__)
#    define SIZEOF_SIZE_T 8
#    define SIZEOF_VOIDP  8
#  elif defined(__i386__)
#    define SIZEOF_SIZE_T 4
#    define SIZEOF_VOIDP  4
#  else
#    error "Unsupported GCC platform"
#  endif
#endif

Are IA64 and x86 64 the same from a C programmer's perspective?

I'd also like to be able to compile on Macs. What do I add?

Edit: I can't use sizeof(), as I'm dealing with untouchable legacy code that use stuff like #if SIZEOF_VOIDP == SIZEOF_LONG. I am also only interested in the architectures, not the actual contents. Note that the precompiler does not allow #if sizeof(size_t) == sizeof(void*).

+2  A: 

Why don't you use sizeof operator?

sizeof(long);
sizeof(int);
sizeof(void*);
el.pescado
I need to comply with legacy code that looks like #ifdef SIZEOF_LONG == SIZEOF_VOIDP...
Jonas Byström
You could define those macros like #define SIZEOF_LONG (sizeof(long)), and they will always be right.
el.pescado
The precompiler (at least msvc's) won't allow them in #if statements.
Jonas Byström
+2  A: 

All those defines look pretty reduntant to me. Just use sizeof(void*) and friends.

If you need to have your constants defined, define them like

#define SIZEOF_VOIDP sizeof(void*)
gnud
A: 

No, it is not complete.

Only sizeof (char) is the same on all platforms, compiler options, ...
All other types are not guaranteed to be the same, to stay the same after compiling with different options, ...

You need

sizeof (short)
sizeof (int)
sizeof (long)
sizeof (long long) // C99
sizeof (float)
sizeof (double)
sizeof (long double) // C99
sizeof (void *)
sizeof (char *)
sizeof (long double *) // C99

...
pmg
Only interested in architectures, don't need the actual contents.
Jonas Byström
+1  A: 

Beware! On Windows, whether you are i386 (i.e. x86_32) or x86_64, you will have sizeof(long) == 4 ! (Or #define SIZEOF_LONG 4). Whereas sizeof(void *) == 8 !

sizeof(long) != sizeof(void *)

Didier Trosset
Does that apply to IA64 as well? Do you know if IA64 and x64 holds any differences from a C programmer's perspective?
Jonas Byström
@Jonas: I don't know. I've never programmed, be it have access to an IA64 system.
Didier Trosset
More info on ILP64, LP64, and LLP64 there: http://www.unix.org/version2/whatsnew/lp64_wp.html
Didier Trosset
+1  A: 

One point to consider about #define SIZEOF_LONG 8 and #define SIZEOF_VOIDP 8.

On HP-UX IA64 this program:

#include <iostream>

int main()
{
#if defined(__ia64__) && defined(__GNUG__)
    std::cout << sizeof(long) << std::endl;
    std::cout << sizeof(void*) << std::endl;
#endif
    return 0;
}

if compiled like this:

g++ -mlp64 main.cpp

gives: 8 8

but if compiled like this:

g++ -milp32 main.cpp

gives 4 4

skwllsp
Hum, do you get some type of #define to identify which mode you've compiled with?
Jonas Byström
As far as I know `__LP64__` and `_LP64` are defined in `-mlp64` mode.
skwllsp
+2  A: 

If you're doing a lot of cross-platform/cross-compiler work then it may be worth adding static asserts for those constants so you can at least catch platform/compiler combinations that are not set in your ifdefs.

In C++ with boost:

#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(sizeof(void*) == SIZEOF_VOIDP)
BOOST_STATIC_ASSERT(sizeof(long)  == SIZEOF_LONG)

If you're working in C there are a couple of questions on here about implementing static assertions in C.

Macs use a customised version of GCC, so many of the constants you use for GCC should also work on the Mac. I typically detect OSX builds with

#ifdef __APPLE__
#endif

but I'm not sure if this is the best way. On my (32-bit) 10.4 OSX install both a long and void* occupy 4 bytes.

Adam Bowen
+6  A: 

How about using your build system to generate these as constants

#include <stdio.h>

int main()
{
   printf(
      "#if !defined ARCH_MODEL_CONSTANTS_H\n"
      "#define ARCH_MODEL_CONSTANTS_H\n"
      "\n"
      "#    define SIZEOF_LONG  %u\n"
      "#    define SIZEOF_VOIDP %u\n"
      "\n"
      "#endif\n",
      (unsigned)sizeof(long),
      (unsigned)sizeof(void *) ) ;

   return 0 ;
}

Provided your build system is consistent, where everything is built with the same options, this builds in implicit portability, and you deal with the problems in your ifdefs where you've got sizeof(long) wrong on 64-bit ia64 and x64 windows (even with the gcc compiler which youve assumed to mean non-windows).

Backing this up with the static asserts mentioned in a different answer would then give you the best of both worlds.

Peeter Joot
Great idea - I can even keep my minimalistic homebrew build system!
Jonas Byström
A: 

SIZEOF_LONG == SIZEOF_VOIDP - dangerous

See data models.

Andrey Karpov