3

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 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;
}
Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • 2
    This is why I hate using the primitive integer types. `` FTW – Mysticial Jul 31 '16 at 06:04
  • @Mysticial - I know what you mean... I have wanted to change to `uint64_t` and friends for at least 5 or 10 years. There's a few non-technical barriers/requirements stopping me. – jww Jul 31 '16 at 06:23

0 Answers0