Есть ли отличия size_t от SIZE_T?

130
19 января 2020, 21:00

До сих пор везде использовал size_t, считая что это целочисленный тип, который адаптируется под разрядность операционной системы (4 байта - для x86, 8 - для x64). И вот для работы с WriteProcessMemory я так же пытался использовать size_t* в качестве последнего аргумента SIZE_T *lpNumberOfBytesWritten - на что получил:

invalid conversion from 'size_t*' to 'SIZE_T*'

Перейдя к typedef-ам я обнаружил следующее для SIZE_T:

typedef ULONG_PTR SIZE_T, *PSIZE_T;
typedef  unsigned long ULONG_PTR, *PULONG_PTR;

причем последняя строка была внутри какого-то #if с комментарием

/*  !_WIN64 */

и следующее для size_t:

typedef __SIZE_TYPE__ size_t;

где __SIZE_TYPE__ , видимо, какой-то макрос (автопереход к нему у меня не работает).

Правильно я понимаю, что они по сути своей идентичны и не зря имеют одинаковое именование, а эта ошибка - лишь формальность, вызванная различием их реализаций?

Answer 1

На моём экземпляре Visual Studio 2017 следующий код даёт такой вывод при различной разрядности проекта:

#include <iostream>
#include <typeinfo>
#include <BaseTsd.h>
#include <cstddef>
int main()
{
    std::cout << typeid(SIZE_T).name() << "\n" << 
                 typeid(size_t).name() << "\n";
}
  • 32 bit

    unsigned long
    unsigned int
    
  • 64 bit

    unsigned __int64
    unsigned __int64
    

Можно заметить, что на 64 разрядной платформе эти типы идентичны. В то же время на 32 разрядной типы хоть и различны (с точки зрения языка), но представляют одинаковый набор возможных значений, т.е. sizeof(int) == sizeof(long) в Windows, хотя в общем случае это не всегда так. Но даже несмотря на совпадение размеров различные типы не всегда совместимы (иначе бы не было ошибки, с которой вы сюда пришли). И, например, следующий код будет корректным для x86, но вызовет ошибку компиляции для x64:

void f(size_t) {}
void f(SIZE_T) {}

Если же посмотреть на описание типов, то можно увидеть следующее:

  • SIZE_T

    The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer.

    This type is declared in BaseTsd.h as follows:

    typedef ULONG_PTR SIZE_T;
    
  • size_t

    The type size_­t is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object ([expr.sizeof]).

По сути, разными словами выражено одно и то же - "тип, позволяющий хранить размер максимально возможного объекта". При этом для size_t беззнаковость указана явно, а вот для SIZE_T она лишь косвенно проскакивает через букву U в ULONG_PTR.

Общий совет такой: если работаете с WinAPI и имеется параметр типа SIZE_T, то этот тип и стоит использовать, во всех остальных ситуациях - следует отдавать предпочтение стандартным типам C++ для увеличения уровня переносимости кода. Понятно, что на стыке двух миров придётся обеспечивать преобразование одного типа в другой. В хорошем решении этой задачи стык этот должен быть достаточно лаконичен и не размазан по всему коду.

Answer 2

Правильно я понимаю, что они по сути своей идентичны и незря имеют одинаковое именование, а эта ошибка - лишь формальность, вызванная различием их реализаций?

Да, они должны быть эквивалентны. (В том смысле, что оба беззнаковые, одинакового размера.)

size_t (или std::size_t) - это стандартный тип из <cstddef>/<stddef.h>. В своем коде лучше использовать именно его.

SIZE_T - тип из WinAPI.

А тип __SIZE_TYPE__ скорее всего встроен в ваш компилятор, поэтому ваша IDE и не может показать его определение.

READ ALSO
signal.h в windows

signal.h в windows

Все источники говорят что, типы sigaction, sigset_t находятся в signalh Эта строчка у меня в самом верху присутствует:

159
Run-Time Check Failure #0 После записи указателя на метод класса

Run-Time Check Failure #0 После записи указателя на метод класса

Делаю колбэк на изменения размеров окна, и реагирования на изменение размера рендерераХорошо, объявил typedef, класс окна и класс рендерера...

158
Как связать dbcc_name из PDEV_BROADCAST_DEVICEINTERFACE и mount point?

Как связать dbcc_name из PDEV_BROADCAST_DEVICEINTERFACE и mount point?

После вставки носителя я получу сначала событие dbch_devicetype с deviceinterface, а затем с volume и если накопитель вставлялся 1, то очевидно оба события будут...

141