你有一个非常有趣和棘手的问题。
简而言之,有两个驱动因素导致竞争类型家族的存在——基于 DWORD 和基于 int:
1) 一方面希望有crosspltformity,另一方面希望有严格的尺寸类型。
2) 人民保守主义。
无论如何,要为您的问题提供完整的详细答案以及该领域足够好的背景,我们必须深入研究计算机的历史。并从计算的早期开始我们的故事。
首先,有一个机器词这样的概念。机器字是大小严格的二进制数据块,可以在特定处理器中自然处理。因此,机器字的大小几乎不依赖于处理器,并且通常等于通用内部处理器寄存器的大小。通常它可以细分为两个相等的部分,处理器也可以将它们作为独立的数据块进行访问。例如,在 x86 处理器上,机器字长为 32 位。这意味着所有通用寄存器(eax、ebx、ecx、edx、esi、edi、ebp、esp 和 eip)具有相同的大小 - 32 位。但其中许多可以作为寄存器的一部分访问。例如,您可以将 eax 作为 32 位数据块、ax、16 位数据块甚至 al 作为 8 位数据块访问。但并不是说这在物理上都是一个 32 位寄存器。我认为您可以在 Wikipedia (http://en.wikipedia.org/wiki/Word_(computer_architecture)) 上找到该领域的非常好的背景。简而言之,机器字是多少位数据块可以用作单个指令的整数操作数。即使在今天,不同的处理器架构也有不同的机器字长。
好的,我们对计算机词有了一些了解。现在是回到计算历史的时候了。第一个流行的 Intel x86 处理器具有 16 位字长。它于 1978 年上市。当时,即使不是主要的编程语言,汇编程序也非常流行。如您所知,汇编程序只是本机处理器语言下的一个非常薄的包装器。因此,它完全依赖于硬件。而当英特尔将他们的新 8086 处理器推向市场时,他们取得成功所需的第一件事就是将新处理器的组装商也推向市场。没有人想要一个没有人知道如何编程的处理器。当英特尔在 8086 的汇编程序中给出不同数据类型的名称时,他们做出了明显的 chois 并将 16 位数据块命名为一个词,因为 8086 的机器字有 16 位大小。机器字的一半称为字节(8 位),用作一个操作数的两个字称为双字(32 位)。英特尔在处理器手册和汇编程序助记符中使用了这个术语(db、dw nd dd 用于字节、字和双字的静态分配)。
多年过去了,1985 年,英特尔推出了 80386 处理器,从 16 位架构转向了 32 位架构。但当时有大量的开发人员习惯于这个词是 16 位值。除此之外,还有大量的软件是用真正的相信这个词是 16 位的。许多已经编写的代码都依赖于字是 16 位这一事实。因此,除了机器字长实际上发生了变化之外,符号保持不变,除了新的数据类型到达汇编器 - 四字(64 位),因为依赖于两台机器的指令词保持不变,但机器词被扩展。以同样的方式,双四字(128 位)现在出现在 64 位 AMD64 架构中。结果我们有
byte = 8 bit
word = 16 bit
dword = 32 bit
qword = 64 bit
dqword = 128 bit
请注意,该类型系列的主要内容是它是强大的类型系列。因为它来自并且在汇编程序中大量使用,所以需要具有恒定大小的数据类型。请注意,岁月流逝,但该系列的数据类型继续具有相同的恒定大小,除了其名称已经没有其原始含义的事实。
另一方面,在同一时期,高级语言也越来越流行。而且由于该语言是在考虑跨平台应用程序开发的,因此从绝对其他角度来看其内部数据类型的大小。如果我正确理解没有一种高级语言没有明确声称其某些内部数据类型具有固定的常量大小,将来永远不会改变。让我们不要像示例那样看 C++。C++ 标准告诉我们:
"The fundamental storage unit in the C++ memory model is the byte. A byte is at
least large enough to contain any member of the basic execution character set and
is composed of a contiguous sequence of bits, the number of which is implementa-
tion-defined. The least significant bit is called the low-order bit; the most
significant bit is called the high-order bit. The memory available to a C++ program
consists of one or more sequences of contiguous bytes. Every byte has a unique
address."
因此,我们可以看到令人惊讶的信息——在 C++ 中,甚至字节都没有任何固定大小。所以即使我们习惯认为有大小 - 8 位,根据 C++,大小不仅可以是 8,还可以是 9、10、11、12 等位。甚至可能是 7 位。
"There are five signed integer types: “signed char”, “short int”, “int”, and
“long int”., and “long long int”. In this list, each type provides at least as
much storage as those preceding it in the list. Plain ints have the natural size
suggested by the architecture of the execution environment; the other signed
integer types are provided to meet special needs."
该引用描述了两个主要主张:
1) sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
2) 普通整数具有执行环境架构所建议的自然大小。这意味着 int 必须具有目标处理器架构的机器字长。
您可以浏览所有 C++ 标准文本,但找不到诸如“int 大小为 4 字节”或“long 长度为 64 位”之类的内容。特定整数 C++ 类型的大小会随着从一种处理器架构转移到另一种,以及从一种编译器转移到另一种而改变。但即使你用 C++ 编写程序,你也会定期面临使用具有众所周知的常量大小的数据类型的要求。
至少早期的编译器开发人员遵循了该标准声明。但现在我们可以看到,人们的保守主义又一次上演了。人们过去认为 int 是 32 位的,可以存储范围从 –2,147,483,648 到 2,147,483,647 的值。早些时候,当行业跨越 16 位和 32 位架构之间的边界时。第二项要求得到严格执行。当您使用 C++ 编译器创建 16 位程序时,编译器使用具有 16 位大小的 int,这是 16 位处理器的“自然大小”,相反,当您使用另一个 C++ 编译器创建 32 位程序但从相同的源代码中,编译器使用了 32 位大小的 int,即 32 位处理器的“自然大小”。如今,如果你看,例如,
总而言之,我们可以看到有两种数据类型系列——基于 dword 和基于 int。第二个动机很明显——跨平台应用程序开发。第一个动机是在考虑变量大小有意义的情况下。例如,除其他外,我们可以提及以下情况:
1)您需要在预定义的众所周知的范围内具有一些价值,并且您需要在类或另一个数据结构中使用它,这些数据结构将在运行时填充到大量实例中。在这种情况下,如果您将使用基于 int 的类型来存储该值,那么它的缺点是在某些架构上会产生巨大的内存开销,并且可能会破坏另一个架构上的逻辑。例如,您需要操作 0 到 1000000 范围内的值。如果您将使用 int 来存储它,如果 int 为 32 位,您的程序将正确运行,如果为 int,则每个值实例将有 4 字节的内存开销将是 64 位,如果 int 是 16 位,则无法正常工作。
2)下一步工作涉及的数据。为了能够在不同的 PC 上正确处理您的网络协议,您需要以基于大小的格式以纯格式指定它,这将逐位描述所有数据包和标头。如果在一台 PC 上,您的协议标头长度为 20 字节,32 位,而在另一台 PC 上,协议标头长度为 28 字节,64 位 int,您的网络通信将完全中断。
3)您的程序需要存储用于某些特殊处理器指令的值,否则您的程序将与用汇编程序编写的模块或代码块进行通信。
4)您需要存储将用于与设备通信的值。每个设备都有自己的规范,描述了需要什么样的输入设备作为输入以及它将以何种形式提供输出。如果设备需要 16 位值作为输入,则无论 int 大小如何,甚至无论安装设备的系统上的处理器使用的机器字长如何,它都必须接收同样的 16 位值。
5)您的算法依赖于整数溢出逻辑。例如,您有 2^16 个条目的数组,并且您希望无限地和连续地遍历它并刷新条目值。如果您将使用 16 位 int,您的程序将完美运行,但当您转向使用 32 位 int 时,您将获得超出范围的数组索引访问。
因此,Microsoft 使用这两种数据类型。在实际数据大小不是很重要的情况下,基于 Int 的类型,在它具有的情况下,基于 DWORD 的类型。即使在这种情况下,Microsoft 也将两者都定义为宏,以便通过为其分配正确的 C++ 等效项,为特定的处理器体系结构和/或编译器提供快速且轻松地采用 Microsoft 使用的虚拟类型系统的能力。
我希望我已经很好地涵盖了有关数据类型的起源及其差异的问题。
因此,我们可以切换到第二个问题,即为什么使用十六进制数字来表示基于 DWORD 的数据类型值。其实有几个原因:
1)如果我们使用严格大小的二进制数据类型,我们可以期望以二进制形式查看它们。
2) 以二进制形式编码的位掩码值很容易理解。同意如果值在下一种形式中,则更容易理解设置了哪些位以及重置了哪些位
1100010001011001
那么如果它将以下一种形式编码
50265
3) 以二进制形式编码的数据和描述的一个基于 DWORD 的值具有恒定长度,而以十进制形式编码的相同数据将具有可变长度。请注意,即使小数以二进制形式编码,也会提供完整的值描述
0x00000100
代替
0x100
二进制编码的这一特性在需要分析大量二进制数据的情况下非常有吸引力。例如,当您的断点被命中时,十六进制编辑器或分析您的程序在调试器中使用的普通内存。同意在弱对齐的可变大小值堆中查看整齐的值列要舒服得多。
因此,我们决定要使用二进制编码。我们有三种选择:使用普通二进制编码、使用八进制编码和使用十六进制编码。人们更喜欢使用十六进制编码,因为它是可用编码集中最短的。只是比较
10010001101000101011001111000
和
0x1234568
你能快速找到下一个值中设置的位数吗?
00000000100000000000000000000
接下来呢?
0x00100000
在第二种情况下,您可以快速将数字分成四个单独的字节
0x00 0x10 0x00 0x00
3 2 1 0
其中第一个数字表示 4 个最高有效位,第二个数字表示另外 4 个最低有效位。在您花费一些时间处理十六进制值之后,您将记住每个十六进制数字的普通位模拟,并将在脑海中一个一个替换,没有任何问题:
0 - 0000 4 - 0100 8 - 1000 C - 1100
1 - 0001 5 - 0101 9 - 1001 D - 1101
2 - 0010 6 - 0110 A - 1010 E - 1110
3 - 0011 7 - 0111 B - 1011 F - 1111
所以,我们只需要一两秒钟就可以发现我们已经设置了第 20 位!
人们使用十六进制是因为它最简短,最容易理解和使用二进制数据编码的形式。