stdint types vs native types: long vs int64_t, int32_t

Viewed 223

Has there been a change in type equivalency of uint64_t, uint32_t, long and int (i.e. the stdint and native compiler types). Or have I run into a g++ bug?

The following code in g++ 8.3 with c++17 options compiles without error. Architecture is arm 32-bit.

std::stringstream os;

void write(long value)
{
    os << value;
}
void write(int64_t value)  // G++ 9.4 error: indistinguishable overload.
{
    os << value;
}
void write(int32_t value)
{
    os << value;
}

long value = 1;
write(longValue);  // g++ 8.3: no matching overload, if the write(long) overload is removed.

The same code compiled with g++ 9.4 with c++17 options gives an error, since the long and in64_t overloads are not distinguishable. (What I would have expected).

But removing the write(long) overload causes g++ 8.3 to complain that there's no matching overload. (Not what I would have expected in any version of the C++ standard).

Honestly, I'm not sure why the gcc 8.3 version works at all. If uint64_t was typedef'ed, the code should work without the write(long) overload Perhaps a bug in gcc 8.3?

While we're at it: how about equivalency of char, uint8_t, int8_t? (would be a great thing if they were distinct). I do seem to remember that wchar_t became a distinct type separate from uint16_t/int16_t in C++(mumble-mumble). Not sure about the rest.

1 Answers

Yes, different CPU architectures have different sizes of fundamental types, and the fixed width aliases map to different types. This differs across operating systems as well; not just architecture. This is normal, not a bug, and generally doesn't change between compiler versions.

To avoid this problem, either provide overloads for only fixed width types, or provide overloads for each fundamental type. Don't mix them.

In this case, it may be better to use a function template instead of overloads:

template<class T>
void write(T value)
{
    os << value;
}

how about equivalency of char, uint8_t, int8_t?

All of those are always distinct types. std::uint8_t - when it is defined at all - is an alias of unsigned char and std::int8_t - when defined - is an alias of signed char. Both of those are distinct from char type.

Related