Почему стандартные типы данных не используются в Win32 API?
Я изучаю программирование Visual С++ Win32 некоторое время.
Почему существуют такие типы данных, как DWORD
, WCHAR
, UINT
и т.д. Вместо, скажем, unsigned long
, char
, unsigned int
и т.д.?
Я должен помнить, когда использовать WCHAR вместо const char *, и это действительно раздражает меня.
Почему не используются стандартные типы данных? Будет ли это помогать, если я буду запоминать эквиваленты Win32 и использовать их для моих собственных переменных?
Ответы
Ответ 1
Да, вы должны использовать правильный тип данных для аргументов для функций, или вы, вероятно, столкнетесь с проблемами.
И причина, по которой эти типы определены так, как они есть, вместо использования int
, char
и т.д., заключается в том, что он удаляет "то, что компилятор считает, что int
должен быть определен как" из интерфейс ОС. Это очень хорошо, потому что, если вы используете компилятор A или компилятор B или компилятор C, все они будут использовать одни и те же типы - только заголовок файла интерфейса библиотеки должен делать правильную вещь, определяющую типы.
Определяя типы, которые не являются стандартными, легко изменить int
с 16 до 32 бит, например. Первые компиляторы C/С++ для Windows использовали 16-битные целые числа. Только в середине-конце 1990 года Windows получила 32-битный API, и до этого момента вы использовали int
, который был 16-бит. Представьте, что у вас есть хорошо работающая программа, в которой используется несколько сотен переменных int
, и внезапно вам нужно изменить ВСЕ эти переменные на что-то еще... Не было бы очень хорошо, правильно - особенно, как НЕКОТОРЫЕ этих переменных НЕ нужно менять, потому что переход на 32-битный int для некоторых из вашего кода не будет иметь никакого значения, поэтому не нужно менять эти биты.
Следует отметить, что WCHAR
НЕ совпадает с const char
- WCHAR
является "широким char", поэтому wchar_t
является сопоставимым типом.
Итак, в принципе, "определить наш собственный тип" - это способ гарантировать, что можно изменить базовую архитектуру компилятора, не изменяя (большую часть) исходного кода. Все крупные проекты, которые выполняют машинное кодирование, делают такие вещи.
Ответ 2
Размеры и другие характеристики встроенных типов, таких как int
и long
, могут варьироваться от одного компилятора к другому, обычно в зависимости от базовой архитектуры системы, на которой работает код.
Например, в 16-разрядных системах, на которых первоначально была реализована Windows, int
составлял всего 16 бит. В более современных системах int
- 32 бита.
Microsoft получает такие типы, как DWORD
, чтобы их размеры оставались одинаковыми в разных версиях их компилятора или других компиляторов, используемых для компиляции кода Windows.
И имена предназначены для отражения концепций базовой системы, определенных Microsoft. A DWORD
- это "двойное слово" (которое, если я правильно помню, имеет 32 бита в Windows, хотя машинное "слово", вероятно, 32 или даже 64 бита в современных системах).
Возможно, было бы лучше использовать типы фиксированной ширины, определенные в <stdint.h>
, такие как uint16_t
и uint32_t
, но они были введены только на язык C по стандарту ISO ISO 1999 (который Microsoft компилятор не полностью поддерживает даже сегодня).
Если вы пишете код, который взаимодействует с Win32 API, вы должны определенно использовать типы, определенные этим API. Для кода, который не взаимодействует с Win32, используйте любые типы, которые вам нравятся, или любые типы, предлагаемые интерфейсом, который вы используете.
Ответ 3
Я думаю, что это историческая катастрофа.
Моя теория заключается в том, что оригинальные разработчики Windows знали, что стандартные размеры типа C зависят от компилятора, то есть один компилятор может иметь 16-разрядное целое число, а другое 32-разрядное целое. Поэтому они решили сделать API-интерфейс Windows переносимым между разными компиляторами с помощью серии typedefs: DWORD
- это 32-разрядное целое без знака, независимо от того, какой компилятор/архитектура вы используете. Естественно, в настоящее время вы будете использовать uint32_t
из <stdint.h>
, но в то время это было недоступно.
Затем, с помощью элемента UNICODE, они получили проблему TCHAR
vs. CHAR
vs. WCHAR
, но эту другую историю.
И тогда он вышел из-под контроля, и вы получите такие приятные вещи, как typedef void VOID, *PVOID;
, которые совершенно бессмысленны.