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
    表示可以对其进行数学运算的整数类型,而
    DWORD
    仅表示某种类型的通用32位值,通常是您不想修改的键、句柄或其他值

你最初的问题是,这些看似疯狂的定义背后是否有某种道理,或者是否有一个你没有遗漏的抽象概念。简单的答案是,这些定义是不断演变的,当时的变化是有意义的。没有特别的抽象,尽管其目的是,如果您编写的代码使用头中定义的类型,那么您应该能够将代码从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;