C Windows数据类型。。。为什么如此冗余/不描述性?
有人能确切地解释一下为什么定义了以下C Windows数据类型。。。为什么如此冗余/不描述性?,c,winapi,types,history,C,Winapi,Types,History,有人能确切地解释一下为什么定义了以下typedefs/#defines吗?与原件相比,它们有什么价值 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
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?
这背后的原因是什么?这是我不理解的抽象概念吗
编辑: 对于那些提到编译器跨兼容性的人: 我的问题不是他们为什么不使用
unsignedlong-long
而不是,比如说,DWORD64
。我的问题是为什么会有人使用DWORD64
而不是ULONG64
(反之亦然)?这两个typedef
ed不是都是64位宽的吗
或者,再举一个例子:即使是在一个“假想的”编译器中,它的目的是在各个方面欺骗我们,ULONG_PTR
和UINT_PTR
和DWORD_PTR
之间有什么区别?这些都是抽象数据类型,不是意味着同一件事吗--SIZE\t
然而,我问他们为什么使用
ULONGLONG
而不是long
——无论long
还是DWORDLONG
,在意义上都没有潜在的差异吗?一个原因是要在C编译器之间保持某种可移植性
特别是DWORD64,从理论上讲,您只需更改DWORD64的定义即可在其他编译器上编译代码。当25年前首次构建Windows API头文件时,
int
为16位,long
为32位。头文件随着时间的推移而不断演变,以反映编译器和硬件中的变化
也是,微软C++不是唯一的Windows编译器文件的C++编译器。当Microsoft添加
size\t
关键字时,并非所有编译器都支持它。但是他们可以很容易地创建一个宏来表示它
此外,还有(或曾经有)自动工具将API头文件从C/C++转换为其他语言。这些工具中的许多最初是为了使用当前(当时)的头定义而编写的。如果微软只是按照你的建议更改头文件以简化它们,那么许多工具将停止工作
基本上,头文件将窗口类型映射到最小公分母,以便多个工具可以使用它们。有时看起来确实有些混乱,我怀疑如果微软愿意抛弃任何向后兼容的假象,他们可以减少大部分混乱。但是这样做会破坏很多工具(更不用说很多文档)
因此,是的,Windows头文件有时是一团糟。这就是我们为进化、向后兼容性和使用多种语言的能力所付出的代价
其他信息:
我同意,乍一看,所有这些定义似乎都很疯狂。但是作为一个看到Windows头文件随着时间的推移而演变的人,我理解它们是如何产生的。这些定义中的大多数在引入时都非常合理,即使现在看起来很疯狂。至于具体的案例ULONGLONG
和DWORD64
,我认为它们是为了一致性而添加的,因为旧的头文件有ULONG
和DWORD
,所以程序员会期望其他两个。至于为什么ULONG
和DWORD
都是同一事物时定义的,我可以想到几种可能性,其中两种是:
- 一个API团队使用了
,另一个团队使用了ULONG
,当头文件被合并时,他们只是保留了这两个文件,而不是通过转换成一个或另一个来破坏代码DWORD
- 一些程序员在
方面的思考比ULONG
更为自如DWORD
表示可以对其进行数学运算的整数类型,而ULONG
仅表示某种类型的通用32位值,通常是您不想修改的键、句柄或其他值DWORD
你最初的问题是,这些看似疯狂的定义背后是否有某种道理,或者是否有一个你没有遗漏的抽象概念。简单的答案是,这些定义是不断演变的,当时的变化是有意义的。没有特别的抽象,尽管其目的是,如果您编写的代码使用头中定义的类型,那么您应该能够将代码从32位移植到64位而不会出现问题。也就是说,
DWORD
在两种环境中都是相同的。但是如果在API指出返回值为HANDLE
时使用DWORD
作为返回值,则会遇到问题。这些冗余名称中的大多数存在主要有两个原因:
- 它们是为向后兼容而保留的历史类型
- 它们是来自不同开发团队的同一类型的不同名称(对于团队来说,在Windows这样一个庞大的项目中保持一致性可能会非常困难)
char
的符号在不同的平台和编译器中可能会有所不同,这就是原因之一。最初的开发人员可能也为将来的字符编码更改保留了这个选项,但当然这不再相关,因为我们现在使用TCHAR
来实现这个目的
在迁移到64位的过程中,他们可能发现他们的一些
DWORD
参数确实需要64位长,并且他们可能将其重命名为DWORD64
,以便这些API的现有用户不会感到困惑
这一个可以追溯到16位时代,当时有16位的常规“近”指针和32位的“远”指针。类型上的
L
前缀代表“long”或“far”,现在没有意义,但现在又回来了
typedef char CHAR;
typedef unsigned __int64 DWORD64; //A 64-bit "double"-word?!
typedef void *PVOID; //Why not just say void*?
typedef void *LPVOID; //What?!
typedef void near *PVOID;
typedef void far *LPVOID;