Type of unsigned long is different from uint32_t and uint64_t on Windows (VS2010)
Asked Answered
A

1

8

On Visual Studio 2010 under Windows 7, 32bit, unsigned long seems to be a distinct type from both uint32_t and uint64_t. See the following test program:

#include <stdint.h>
#include <stdio.h>

template<class T, class U>
struct is_same_type
{
    static const bool value = false;
};
template<class T>
struct is_same_type<T, T>
{
    static const bool value = true;
};

#define TO_STRING(arg)        TO_STRING_IMPL(arg)
#define TO_STRING_IMPL(arg)   #arg

#define PRINT_SAME_TYPE(type1, type2) printf("%s (size=%d) %s %s (size=%d)\n", \
    TO_STRING(type1), int(sizeof(type1)), \
    is_same_type<type1, type2>::value ? "==" : "!=", \
    TO_STRING(type2), int(sizeof(type2)))


int main(int /*argc*/, const char* /*argv*/[])
{
    PRINT_SAME_TYPE(uint32_t, unsigned long);
    PRINT_SAME_TYPE(uint64_t, unsigned long);
    return 0;
}

I'd expect it to print either

uint32_t (size=4) != unsigned long (size=8)
uint64_t (size=8) == unsigned long (size=8)

(which I get on x86_64 Linux) or

uint32_t (size=4) == unsigned long (size=4)
uint64_t (size=8) != unsigned long (size=4)

assuming of course that long is not longer than 64bits.

On Windows however, I get the baffling

uint32_t (size=4) != unsigned long (size=4)
uint64_t (size=8) != unsigned long (size=4)

which means that there are two distinct 32bit unsigned types. Is this allowed by the C++ standard? Or is this a bug in the Visual C++ compiler?

Abutilon answered 23/7, 2012 at 11:18 Comment(1)
Yes, there are two distinct unsigned 32-bit unsigned types. uint32_t is a typedef for unsigned int. And unsigned int != unsigned long.Skyscraper
G
11

There are two distinct 32-bit, unsigned types

Yes, there are. Both int and long are represented by 32 bits.

Is this allowed by the C++ standard?

Yes. The specification states (C++11 §3.9.1[basic.fundamental]/2):

There are five standard signed integer types : signed char, short int, int, long int, and long long int. In this list, each type provides at least as much storage as those preceding it in the list.

For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type...each of which occupies the same amount of storage and has the same alignment requirements as the corresponding signed integer type

Note that despite the fact that int and long are represented by the same number of bits, they are still different types (so, for example, they are treated differently during overload resolution).

Gershom answered 23/7, 2012 at 17:46 Comment(2)
The last point is awesome for kinda-meta-programming and preferring certain overloads by having one take an int, the other take a long and passing a literal 0.Piperpiperaceous
Thanks for the explanation, I remember now :) From a historical perspective this makes sense, but I still find it a rather unfortunate aspect of the C++ type system. In my case I got tripped up because I had template overloads for all int*_t and uint*_t types, but they didn't catch all integer types.Abutilon

© 2022 - 2024 — McMap. All rights reserved.