1

In c++, is there any way to guarantee that a long is 4 bytes? Perhaps a compiler flag for g++?

We are reusing some windows code in a linux program, and in windows a long is 4 bytes, but on my linux machine a long is 8 bytes. We can't go and change all the longs to ints because that would break the windows code.

The reason I need to guarantee longs are 4 bytes is because in certain parts of the code, we have a union of a struct and a char array, and when compiling for 64bit linux, the char array does not line up with the other struct.

Here are some code snippits for clarification:

struct ABC {
    unsigned long  data1;
    unsigned short data2;
    unsigned short data3;
    unsigned char  data4[8];
};
//sizeof(ABC) (32 bit): 16, sizeof(ABC) (64 bit): 24

union ABC_U {
    ABC abc;
    unsigned char bytes[16];
};

EDIT:

I forgot to mention, this problem only came up when trying to compile for 64 bit. Windows seems to like to keep longs 4 bytes regardless of architecture, whereas linux g++ usually makes longs the same size as pointers.

I'm leaning towards using a uint32_t here because this particular structure isn't used in the Windows code, and that wouldn't affect the program globally. Hopefully there aren't any other sections of the code where this will be a problem.

I found the compiler flag -mlong32, but this also forces pointers to be 32 bits which is undesirable, and as it forces nonstandard behavior would likely break the ABI like PascalCuoq mentioned.

Brian Schlenker
  • 4,966
  • 6
  • 31
  • 44
  • 5
    How about specifying the integer size in bits, like uint64? – user2613971 Aug 14 '13 at 17:29
  • @user2613971: Or `uint64_t`, which has the virtue of being standard -- though it looks like the OP is looking for `int32_t`. – Keith Thompson Aug 14 '13 at 17:41
  • To support such a switch, your implementation would need to ship an alternate Standard Library compiled with `sizeof(long)==4`. But this does not scale: if you have N such options, you need to ship 2^N Standard Library implementations – MSalters Aug 15 '13 at 07:33

3 Answers3

4

You can use int32_t from stdint.h.

3

Instead of using int and long, you will likely want to create a header file that uses typedef's (preferred) or preprocessor macros to define common typenames for you to use.

#ifdef _WINDOWS
typedef unsigned long uint32;
#else
typedef unsigned int uint32;
#endif

In your union, you would use uint32 instead of long.

The header file stdint.h does exactly this, but is not always installed as a standard header file with every compiler. Visual Studio (for example) does not have it by default. You can download it from http://msinttypes.googlecode.com/svn/trunk/stdint.h if you would prefer to use it instead.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Visual Studio *does* have it by default. – Benjamin Lindley Aug 14 '13 at 17:56
  • @BenjaminLindley: I believe a recent version does but that is new. – Eric Postpischil Aug 14 '13 at 17:56
  • @Benjamin: That depends on which version of VS you are using. – Zac Howland Aug 14 '13 at 17:57
  • Well it's had it since 2010 (before it was part of the C++ standard), and if you say "Visual Studio does not have it", in the present tense, without a version qualification, I think it's only reasonable to assume you are referring to the most recent commercially available edition. – Benjamin Lindley Aug 14 '13 at 17:59
  • It only had it after you installed the service patch (SP2 if I remember correctly). It was not installed with the original 2010 release. The point was that it may or may not be installed, so you can download it (if you wish to use it), or write your own. – Zac Howland Aug 14 '13 at 18:09
0

You want the compiler to generate code where long is 32-bit.

Compile the entire codebase with -m32. This will generate code in the old IA-32 instruction set, which is still widely supported library-wise(*), and where long is traditionally 32-bit like int.

(*) You may need to install these libraries in your Linux distribution, and you may have to ask your users to install them.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • The problem with this is that we are using the rpm library, and if a 32 bit program uses this library on a 64 bit machine, the rpm database tends to get corrupted, and it becomes a hassle to use programs that access these databases, like yum. – Brian Schlenker Aug 14 '13 at 17:43
  • 1
    @BrianSchlenker Well even if it was possible to force `long` to be 32-bit through an option while generating x86-64 code, it would break the ABI and prevent linking with **any** library, including but not limited to rpm. So the answer to your question augmented with this information is “no, there is no way to force a long to be 4 bytes”. – Pascal Cuoq Aug 14 '13 at 17:50
  • 1
    Thanks, that makes sense. Seems like the only way will be to change the type from long to something else and hopefully not break any of the Windows code. – Brian Schlenker Aug 14 '13 at 17:56