9

我试图理解为什么 DWORD 值经常在 MSDN 上以十六进制描述。

我分析这个的原因是因为我试图从根本上理解为什么所有这些不同的数字数据类型存在。一位当地的导师向我暗示,DWORD 和其他 Microsoft 类型的创建与处理器的发展有关。这为我理解这些数据类型提供了意义和背景。我想要更多的背景和背景。

无论哪种方式,我都可以使用一些解释或一些资源来说明如何记住 DWORD、无符号整数、字节、位、WORD 等之间的区别。

总之,我的问题是:1)为什么 DWORD 用十六进制表示?2)您能否提供有关数值数据类型之间差异以及创建它们的原因的资源?

4

5 回答 5

10

计算机中的所有内容都是一堆 0 和 1。但是用二进制写一个完整的 DWORD 是相当乏味的:

00000000 11111111 00000000 11111111

为了节省空间和提高可读性,我们喜欢把它写成更短的形式。十进制是我们最熟悉的,但不能很好地映射到二进制。八进制和十六进制映射非常方便,与二进制位完全对齐:

// each octal digit is exactly 3 binary digits
01 010 100 binary  =  124 octal

// each hexadecimal digit is exactly 4 binary digits
0101 0100 binary   =  54 hexadecimal

由于十六进制与 8 位字节(2 个十六进制数字组成一个字节)很好地对齐,因此符号卡住了,这就是最常用的。使用位掩码时,它更容易阅读、更容易理解、更容易排列。

识别正在使用哪个碱基的常规简写:

  1234543 = decimal
 01234543 = octal (leading zero)
0x1234543 = hexadecimal (starts with 0x)

至于你关于 BYTE、WORD、DWORD 等的问题......

计算机开始有点。只有 1 或 0。他在最初的 Tron 中有一个客串。

字节长 8 位(嗯,从前有 7 位字节,但我们可以忽略这些)。这允许您有一个从 0 到 255 的数字,或从 -128 到 127 的有符号数字。比仅 1/0 更好,但仍然有限。您可能听说过“8 位游戏”。这就是我们所指的。该系统是围绕字节构建的。

然后计算机发展到具有 16 位寄存器。这是 2 个字节,并被称为 WORD(不,我不知道为什么)。现在,数字可以是 0-65535 或 -32768 到 32767。

我们继续需要更多的能力,计算机被扩展到 32 位寄存器。4 个字节,2 个字,也称为 DWORD(双字)。时至今日,您可以在“C:\Windows”中查看“system”(旧的 16 位部件)和“system32”(新的 32 位组件)的目录。

然后是 QWORD(四字)。4 个字,8 个字节,64 位。听说过 Nintendo-64 吗?这就是名字的由来。现代建筑现在在这里。cpu 的内部包含 64 位寄存器。您通常可以在此类 CPU 上运行 32 位或 64 位操作系统。

这包括位、字节、字、双字。这些是原始类型,通常用于标志、位掩码等。如果要保存实际数字,最好使用有符号/无符号整数、长整数等。

我没有介绍浮点数,但希望这有助于总体思路。

于 2011-04-13T21:11:30.387 回答
4

当 DWORD 常量用作可以按位方式进行或运算的标志时,它们通常以十六进制编写。它更容易看出是这样的。这就是为什么您会看到 0x01、0x02、0x04、0x08、0x10、0x20 等。程序员只是将这些值识别为只有一个位集的二进制表示。

当它是一个枚举时,您会看到 0x01、0x02、0x03 等。它们通常仍以十六进制编写,因为程序员往往会养成这些习惯!

于 2011-04-13T20:38:13.337 回答
1

只是为了记录,16位无符号数据被命名为WORD,因为当时计算机有16位寄存器。

在计算机历史上,8 位数据是您可以存储在寄存器中的最大数据。由于它可以存储 ascii 字符,因此通常称为 CHAR。

但是 16 位计算机出现了,CHAR 不适合命名 16 位数据。因此 16 位数据通常被称为 WORD,因为它是您可以存储在一个寄存器中的最大数据单位,并且可以很好地类比为 CHAR 制作的数据。

因此,在某些计算机上,使用不同的 CPU WORD 通常是指寄存器的大小。在 Saturn CPU 上,使用 64 位寄存器,一个 WORD 是 64 位。

当 32 位 x86 处理器问世时,出于兼容性原因,WORD 保留为 16 位,并创建了 DWORD 以将其扩展到 32 位。QWORD 和 64 位也是如此。

至于为什么通常使用十六进制来描述一个 WORD,它必须与与它的寄存器来源相关的 WORD 定义的性质有关。在汇编程序中,您使用十六进制来描述数据,因为处理器只知道二进制整数(0 和 1)。十六进制是使用二进制的更紧凑的方式,并且仍然保留它的一些属性。

于 2011-04-25T02:25:39.983 回答
1

你有一个非常有趣和棘手的问题。

简而言之,有两个驱动因素导致竞争类型家族的存在——基于 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 位!

人们使用十六进制是因为它最简短,最容易理解和使用二进制数据编码的形式。

于 2012-12-06T20:11:53.863 回答
0

详细说明蒂姆的答案,这是因为将十六进制转换为二进制并返回非常容易 - 每个十六进制数字是 4 个二进制数字:

0x1 = 0001
0x2 = 0010
...
0xD = 1101
0xE = 1110
0xF = 1111

所以,0x2D=0010 1101

于 2011-04-13T21:15:12.097 回答