I'm trying to understand the requirements for selecting a built-in 64-bit data type using either long
or long long
. I'm having trouble understanding the type equivalence and the alignment requirements of long
versus long long
.
What is the best practice or criteria when selecting long
versus long long
as a 64-bit type under LP64/ILP64/LLP64 data models?
Here are some related questions. They completely cover other topics, like sizeof(long) <= sizeof(long long)
, but they don't quite have a treatment of equivalence or alignment expectations. They also rely heavily on non-built-in types, like uint64_t
.
- The UNIX System - 64bit and Data Size Neutrality
- What's the difference between unsigned long/long/int in c/c++?
- Better to use long or long long in 64 bit
- Specifying 64-bit unsigned integer literals on 64-bit data models
The background information is code similar to the following to select a built-in 64-bit type to use:
#if _LP64 || __LP64__ || _ILP64 || __ILP64__
typedef my_u64 unsigned long;
#else
typedef my_u64 unsigned long long;
#endif
i686 and ARMv7 and below are fine with using typedef my_u64 unsigned long long
.
First problem case
On a x86_64 (AMD64) machine, if typedef my_u64 unsigned long
is in effect (due to LP64
), then it results in a compile error:
$ gcc -mrdrnd test.cc -o test.exe
test.cc: In function ‘int main(int, char**)’:
test.cc:18:22: error: invalid conversion from ‘my_u64* {aka long unsigned int*}’ to ‘long long unsigned int*’ [-fpermissive]
_rdrand64_step(&val);
^
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/x86intrin.h:46:0,
from test.cc:2:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/immintrin.h:166:1: note: initializing argument 1 of ‘int _rdrand64_step(long long unsigned int*)’
_rdrand64_step (unsigned long long *__P)
^
Second problem case
On a Aarch64 (ARM64) machine, if typedef my_u64 unsigned long long
is in effect (to fix the x86_64 error), then it results in a compile error:
$ gcc test.cc -o test.exe
test.cc: In function ‘int main(int, char**)’:
test.cc:21:16: error: invalid conversion from ‘my_u64* {aka long long unsigned int*}’ to ‘const uint64_t* {aka const long unsigned int*}’ [-fpermissive]
vld1q_u64(val);
^
In file included from test.cc:4:0:
/usr/lib/gcc/aarch64-linux-gnu/4.9/include/arm_neon.h:17003:1: note: initializing argument 1 of ‘uint64x2_t vld1q_u64(const uint64_t*)’
vld1q_u64 (const uint64_t *a)
^
$ cat test.cc
#if __x86_64__
#include <x86intrin.h>
#elif __aarch64__
#include <arm_neon.h>
#include <arm_acle.h>
#endif
#if _LP64 || __LP64__
typedef unsigned long my_u64;
#else
typedef unsigned long long my_u64;
#endif
int main(int argc, char* argv[])
{
#if __x86_64__
my_u64 val;
_rdrand64_step(&val);
#elif __aarch64__
my_u64 val[2];
vld1q_u64(val);
#endif
return 0;
}