3

According to this MSDN page, a data type LONGLONG is defined as below.

#if !defined(_M_IX86)
 typedef __int64 LONGLONG; 
#else
 typedef double LONGLONG;
#endif

And it says LONGLONG is a 64-bit signed integer. But double is a floating-point type, not an integer type. So, do I find a typo? Or am I missing a point?

op ol
  • 705
  • 4
  • 11
  • 4
    No it's not but it's a bit more complicated. Here's an extract from winnt.h https://pastebin.com/raw/Zz8Qbrb9 it's really for architectures/compiler that would know about double (which is ancient, 40 years old) but don't know about 64-bit sized integer, a best (blittable, binary compatible) effort. For example, I think VBA 32-bit doesn't have any int64 integer (LongLong) so developers use double for passing an int64 through apis. It's a similar scenario. – Simon Mourier May 25 '21 at 08:45
  • @SimonMourier That's good to remind that eventually a compiler decides how to read double. But two things confuse me. 1. Why did Microsoft choose a double which is already used against human convention or standards? 2. [This](https://learn.microsoft.com/en-us/cpp/cpp/data-type-ranges?view=msvc-160&viewFallbackFrom=vs-2019) page says double is 64bit floating point type in microsoft c++ 32bit and 64bit compilers. In my understanding winapi c++ code is also compiled in Visual Studio IDE. But why is double specially interpreted in that context? – op ol May 25 '21 at 09:07
  • 1
    Humans are really out of the loop here. As for standards and conventions, I told you, double is the only ancient well-known/standardized type that is 64-bit. But fear nothing, no recent (recent like 20 years) Microsoft Compiler will end up compiling LONGLONG as a double, even if you compile as x86. This is really an edge case today, but try to think yourself 25 years ago. – Simon Mourier May 25 '21 at 09:21
  • @SimonMourier Oh, I'm sorry I misunderstood. I thought you said like 'double is the same as 64bit integer type'. Now I get the point. I should rather learn English more.. Thank you. – op ol May 25 '21 at 09:42

2 Answers2

4

This is a documentation bug. It looks to be a lossy conversion from source to documentation1. The actual definition in winnt.h is a fair bit more complex:

//
// __int64 is only supported by 2.0 and later midl.
// __midl is set by the 2.0 midl and not by 1.0 midl.
//

#define _ULONGLONG_
#if (!defined (_MAC) && (!defined(MIDL_PASS) || defined(__midl)) && (!defined(_M_IX86) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)))
typedef __int64 LONGLONG;
typedef unsigned __int64 ULONGLONG;

#define MAXLONGLONG                         (0x7fffffffffffffff)


#else

#if defined(_MAC) && defined(_MAC_INT_64)
typedef __int64 LONGLONG;
typedef unsigned __int64 ULONGLONG;

#define MAXLONGLONG                      (0x7fffffffffffffff)


#else
typedef double LONGLONG;
typedef double ULONGLONG;
#endif //_MAC and int64

#endif

To understand what's going on, let's strip this down by removing everything not immediately relevant.

  • Assume that defined(_MAC) evaluates to 0.
  • Assume that defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64 evaluates to 1. That appears to be true even going back as far as Visual C++ 6.0.
  • Strip symbols not relevant here (_ULONGLONG_, ULONGLONG, MAXLONGLONG).
  • Apply indentation without changing any other semantics.

The definition is now a lot easier to parse:

//
// __int64 is only supported by 2.0 and later midl.
// __midl is set by the 2.0 midl and not by 1.0 midl.
//

#if !defined(MIDL_PASS) || defined(__midl)
    typedef __int64 LONGLONG;
#else
    typedef double LONGLONG;
#endif

With that it should be clear that the conditional is a guarding the MIDL compiler (not the C++ compiler). The comment above has rationale, too: Version 1 of the MIDL compiler2 didn't support __int64 as a keyword, but version 2 (and later) do.

Translated into English: If this code isn't parsed by the MIDL compiler, or the MIDL compiler's version is 2 or above, alias LONGLONG with __int64. Otherwise (that is, using the MIDL compiler version 1), pick a double as a best effort.

This is of little practical use today. You can assume that LONGLONG is an alias for __int64, regardless of whether the definition is pulled in by the MIDL or C++ compiler. I wasn't able to find a version history for MIDL.exe, but I assume that version 1 is "ancient".


1 I'm reluctant to accept that having .NET developers write the tooling to generate C documentation from source was a Good Idea™.
2 This refers to the compiler version, not the MIDL language version.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
2

With your code snippet, I think it is approach to guarantee that LONGLONG is 64bit under your environment Because double is the only 64bit type which is supported by _M_IX86 in the standard, maybe POSIX. The standard has no __int64 type.

999
  • 21
  • 1