Тип unsigned long отличается от uint32_t и uint64_t в Windows (VS2010).

В Visual Studio 2010 под 32-разрядной версией Windows 7 тип unsigned long отличается как от uint32_t, так и от uint64_t. См. следующую тестовую программу:

#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;
}

Я ожидаю, что он напечатает либо

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

(который я получаю на x86_64 Linux) или

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

при условии, конечно, что long не длиннее 64 бит.

Однако в Windows меня сбивает с толку

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

это означает, что существует два различных 32-битных беззнаковых типа. Разрешено ли это стандартом С++? Или это ошибка в компиляторе Visual C++?


person tbleher    schedule 23.07.2012    source источник
comment
Да, есть два разных беззнаковых 32-битных беззнаковых типа. uint32_t — это typedef для беззнакового целого числа. И unsigned int != unsigned long.   -  person Hans Passant    schedule 23.07.2012


Ответы (1)


Существует два различных 32-битных беззнаковых типа.

Да это так. И int, и long представлены 32 битами.

Разрешено ли это стандартом С++?

да. В спецификации указано (С++ 11 §3.9.1 [basic.fundamental]/2):

Существует пять стандартных типов целых чисел со знаком: signed char, short int, int, long int и long long int. В этом списке каждый тип обеспечивает не меньше места для хранения, чем предшествующие ему в списке.

Для каждого стандартного целочисленного типа со знаком существует соответствующий (но другой) стандартный целочисленный тип без знака... каждый из которых занимает тот же объем памяти и имеет те же требования к выравниванию, что и соответствующий целочисленный тип со знаком.

Обратите внимание, что, несмотря на то, что int и long представлены одним и тем же количеством битов, они по-прежнему относятся к разным типам (поэтому, например, при разрешении перегрузки они обрабатываются по-разному).

person James McNellis    schedule 23.07.2012
comment
Последний пункт отлично подходит для своего рода мета-программирования и предпочтения определенных перегрузок, когда один принимает int, другой принимает long и передает литерал 0. - person Xeo; 23.07.2012
comment
Спасибо за объяснение, теперь я вспомнил :) С исторической точки зрения это имеет смысл, но я все еще нахожу это довольно неудачным аспектом системы типов C++. В моем случае я споткнулся, потому что у меня были перегрузки шаблонов для всех типов int*_t и uint*_t, но они не перехватывали все целочисленные типы. - person tbleher; 24.07.2012