Windows 数据类型...为什么如此冗余/缺乏描述性?
有人能确切地解释一下为什么定义了以下 typedef
s/#define
s 吗?与原件相比,它们有什么价值?
typedef char CHAR;
#define CONST const
typedef float FLOAT;
typedef unsigned __int64 DWORD64; //A 64-bit "double"-word?!
typedef ULONGLONG DWORDLONG; //What's the difference?
typedef ULONG_PTR DWORD_PTR; //What's the difference?
typedef long LONG_PTR; //Wasn't INT_PTR enough?
typedef signed int LONG32; //Why not "signed long"?
typedef unsigned int UINT; //Wait.. UINT is "int", "LONG" is also int?
typedef unsigned long ULONG; //ULONG is "long", but LONG32 is "int"? what?
typedef void *PVOID; //Why not just say void*?
typedef void *LPVOID; //What?!
typedef ULONG_PTR SIZE_T; //Why not just size_t?
最重要的是:
#define VOID void //Assuming this is useful (?), why not typedef?
这些背后的原因是什么?这是我不理解的某种抽象吗?
编辑:
对于那些提到编译器交叉兼容性的人:
我的问题是不是为什么他们不使用unsigned long long
而不是说, ,DWORD64
。我的问题是为什么有人会使用 DWORD64
而不是 ULONG64
(反之亦然)?这两个 typedef 不是都是 64 位宽吗?
或者,再举一个例子:即使在一个“假设的”编译器中,它在各个方面都在欺骗我们,ULONG_PTR
和 UINT_PTR
和 之间有什么区别? DWORD_PTR?这些抽象数据类型不都意味着同样的事情吗——
SIZE_T
?
然而,我am问为什么他们使用 ULONGLONG
而不是 long long
——这两者在含义上是否存在任何潜在的差异,而 没有涵盖long long
还是 DWORDLONG
?
Could someone please exactly why the following typedef
s/#define
s have been defined? What value do they have, compared to the originals?
typedef char CHAR;
#define CONST const
typedef float FLOAT;
typedef unsigned __int64 DWORD64; //A 64-bit "double"-word?!
typedef ULONGLONG DWORDLONG; //What's the difference?
typedef ULONG_PTR DWORD_PTR; //What's the difference?
typedef long LONG_PTR; //Wasn't INT_PTR enough?
typedef signed int LONG32; //Why not "signed long"?
typedef unsigned int UINT; //Wait.. UINT is "int", "LONG" is also int?
typedef unsigned long ULONG; //ULONG is "long", but LONG32 is "int"? what?
typedef void *PVOID; //Why not just say void*?
typedef void *LPVOID; //What?!
typedef ULONG_PTR SIZE_T; //Why not just size_t?
And, best of all:
#define VOID void //Assuming this is useful (?), why not typedef?
What's the reasoning behind these? Is it some sort of abstraction I'm not understanding?
Edit:
For those people mentioning compiler cross-compatilibity:
My question is not about why they didn't use unsigned long long
instead of, say, DWORD64
. My question is about why would anyone use DWORD64
instead of ULONG64
(or vice-versa)? Aren't both of those typedef
ed to be 64 bits wide?
Or, as another example: Even in a "hypothetical" compiler that was meant to deceive us in every respect, what would be the difference between ULONG_PTR
and UINT_PTR
and DWORD_PTR
? Aren't those all abstract data types just meaning the same thing -- SIZE_T
?
However, I am asking why they used ULONGLONG
instead of long long
-- is there any potential difference in meaning, covered by neither long long
nor DWORDLONG
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
大多数这些冗余名称的存在主要有两个原因:
char
的符号可能因平台和编译器而异,所以这是原因之一。最初的开发人员可能也将其保留为未来字符编码的更改,但当然这不再相关,因为我们现在为此目的使用TCHAR
。在迁移到 64 位的过程中,他们可能发现一些
DWORD
参数确实需要 64 位长,并且他们可能将其重命名为DWORD64
,以便现有用户这些 API 并没有混淆。这可以追溯到 16 位时代,当时有常规的 16 位“近”指针和 32 位“远”指针。类型上的
L
前缀代表“long”或“far”,现在没有意义,但在那些日子里,它们可能是这样定义的:更新: As对于
FLOAT
、UINT
和ULONG
,鉴于未来的变化,这些只是“越抽象越好”的示例。请记住,Windows 也可以在 x86 以外的平台上运行 - 您可以想到一种体系结构,其中浮点数以非标准格式表示,并且 API 函数经过优化以利用这种表示形式。这可能会与 C 的float
数据类型发生冲突。Most of these redundant names exist primarily for two reasons:
The signedness of
char
can vary across platforms and compilers, so that's one reason. The original developers might have also kept this open for future changes in character encodings, but of course this is no longer relevant since we useTCHAR
now for that purpose.During the move to 64-bit, they probably discovered that some of their
DWORD
arguments really needed to be 64 bits long, and they probably renamed itDWORD64
so that existing users of those APIs weren't confused.This one dates back to the 16-bit days, when there were regular "near" pointers which were 16-bit and "far" pointers that were 32-bit. The
L
prefix on types stands for "long" or "far", which is meaningless now, but back in those days, these were probably defined like this:Update: As for
FLOAT
,UINT
andULONG
, these are just examples of "more abstraction is good", in view of future changes. Keep in mind that Windows also runs on platforms other than x86 -- you could think of an architecture where floating-point numbers were represented in a non-standard format and the API functions were optimized to make use of this representation. This could then be in conflict with C'sfloat
data type.25 年前首次构建 Windows API 头文件时,
int
为 16 位,long
为 32 位。头文件随着时间的推移而不断发展,以反映编译器和硬件的变化。此外,Microsoft C++ 并不是唯一可以使用 Windows 头文件的 C++ 编译器。当 Microsoft 添加
size_t
关键字时,并非所有编译器都支持它。但他们可以轻松创建一个宏SIZE_T
来表达它。此外,还有(或曾经)将 API 头文件从 C/C++ 转换为其他语言的自动化工具。其中许多工具最初是为了与当前(当时)的标头定义一起使用而编写的。如果微软只是按照您的建议更改头文件以简化它们,那么许多工具将停止工作。
基本上,头文件将 Windows 类型映射到最小公分母,以便多个工具可以使用它们。有时确实看起来很混乱,我怀疑如果微软愿意放弃任何向后兼容的表象,他们可以减少很大一部分混乱。但这样做会破坏很多工具(更不用说很多文档)。
所以,是的,Windows 头文件有时是一团糟。这就是我们为进化、向后兼容性和使用多种语言的能力所付出的代价。
附加信息:
我同意乍一看所有这些定义似乎都很疯狂。但作为一个见证了 Windows 头文件随时间演变的人,我了解它们是如何产生的。这些定义中的大多数在引入时都非常有意义,即使现在它们看起来很疯狂。至于具体情况
ULONGLONG
和DWORD64
,我想添加它们是为了保持一致性,因为旧的头文件有ULONG
和DWORD
,因此程序员会期望其他两个。至于为什么ULONG
和DWORD
是同一个东西,却又被定义,我可以想到几种可能性,其中两种是:ULONG
和另一个使用DWORD
,当头文件被合并时,他们只是保留两者,而不是通过转换为其中一个来破坏代码。ULONG
来思考,而不是用DWORD
来思考。ULONG
表示可以进行数学计算的整数类型,而DWORD
仅表示某种通用 32 位值,通常是键、句柄或您不想修改的其他值。您最初的问题是,这些看似疯狂的定义背后是否有一些推理,或者是否有一个您没有错过的抽象概念。简单的答案是定义不断演变,这些变化在当时是有意义的。没有特定的抽象,尽管目的是如果您编写代码以使用标头中定义的类型,那么您应该能够将代码从 32 位移植到 64 位没有麻烦。也就是说,
DWORD
在两种环境中都是相同的。但是,如果您在 API 指示返回值为HANDLE
时使用DWORD
作为返回值,则会遇到麻烦。When the Windows API header files were first built 25 years ago, an
int
was 16 bits and along
was 32 bits. The header files have evolved over time to reflect changes in compilers and in hardware.Also, Microsoft C++ isn't the only C++ compiler out there that works with the Windows header files. When Microsoft added the
size_t
keyword, not all compilers supported it. But they could easily create a macro,SIZE_T
, to express it.Also, there are (or were) automated tools that convert the API header files from C/C++ to other languages. Many of those tools were originally written to work with the current (at the time) header definitions. If Microsoft were to just change the header files to streamline them as you suggest, many of those tools would stop working.
Basically, the header files map Windows types to a least common denominator so that multiple tools can work with them. It does seem to be something of a mess at times, and I suspect that if Microsoft were willing to throw out any semblance of backward compatibility, they could reduce a large part of the mess. But doing so would break a lot of tools (not to mention a lot of documentation).
So, yes, the Windows header files are sometimes a mess. That's the price we pay for evolution, backward compatibility, and the ability to work with multiple languages.
Additional info:
I'll agree that at first glance all those definitions seem crazy. But as one who has seen the Windows header files evolve over time, I understand how they came about. Most of those definitions made perfect sense when they were introduced, even if now they look crazy. As for the specific case
ULONGLONG
andDWORD64
, I imagine that they were added for consistency, as the old header files hadULONG
andDWORD
, so programmers would expect the other two. As for whyULONG
andDWORD
were both defined when they are the same thing, I can think of several possibilities, two of which are:ULONG
and another usedDWORD
, and when header files were consolidated they just kept both rather than breaking code by converting to one or the other.ULONG
thanDWORD
.ULONG
implies an integer type that you can do math on, whereasDWORD
just implies a generic 32-bit value of some sort, typically something that is a key, handle, or other value that you wouldn't want to modify.Your initial question was whether there was some reasoning behind the seemingly crazy definitions, or if there's an abstraction you're not missing. The simple answer is that the definitions evolved, with the changes making sense at the time. There's no particular abstraction, although the intent is that if you write your code to use the types that are defined in the headers, then you should be able to port your code from 32-bit to 64-bit without trouble. That is,
DWORD
will be the same in both environments. But if you useDWORD
for a return value when the API says that the return value isHANDLE
, you're going to have trouble.原因之一是保持 C 编译器之间的某种可移植性。
特别是DWORD64,理论上你只需要改变DWORD64的定义就可以让代码在其他编译器上编译。
One reason is to maintain some kind of portability between C compilers.
In particular DWORD64, in theory you just need to change the definition of DWORD64 to get the code compiling on other compilers.