BYTE=8位
,
WORD=16位
,
DWORD=32位
(双字)这些术语来自于Intel 8086指令助记符和文档。 这只是术语,目前并不意味着运行代码的实际机器上的“机器字”(machine word)的大小。
我的猜测:
这些C类型名称最初引入的原因可能与C99标准化 uint8_t
,uint16_t
和uint32_t
相同。 思想可能是允许具有不兼容ABI(例如16比特与32比特的int
)的C实现仍能编译使用WinAPI的代码,因为ABI使用DWORD
而不是long
或int
在struct
,函数参数/返回值中。
随着Windows的发展,足够多的代码以各种方式依赖于WORD和DWORD的确切定义,MS决定标准化精确的typedef
。 这与C99 uint16_t
的想法不同,您不能假设它是unsigned short
。
正如@supercat所指出的那样,这可能对别名规则很重要。例如,如果您通过DWORD*
修改unsigned long []
数组,则保证它将按预期工作。 但是,如果您通过DWORD*
修改unsigned int []
数组,则编译器可能会假设这不会影响它已经在寄存器中具有的数组值。 这对于printf
格式字符串也很重要。(C99的<stdint.h>
解决方案是像PRIu32
这样的预处理器宏。)
或者,也许想法仅仅是使用与汇编相匹配的名称,以确保没有人会对类型的宽度感到困惑。 在Windows的早期时期,直接使用asm编写程序(而不是C)很受欢迎。 WORD/DWORD使得为用汇编语言编写的人员提供更清晰的文档。
也许这个想法只是为了提供固定宽度类型以便于可移植代码。例如,对于SUNOS,使用适当的类型来定义
#ifdef SUNOS
。目前而言,这就是它的全部用处,正如你所注意到的:
“Windows API如何能够typedef unsigned short WORD;并且说WORD是一个16位无符号整数,而C标准本身并不保证short始终是16位呢?”
你是正确的,记录精确的
typedef
意味着在使用不同ABI的系统中(例如其中
long
为64位或
short
为32位的系统),无法正确地实现WinAPI头文件。这也是x86-64 Windows ABI将
long
作为32位类型的部分原因。x86-64 System V ABI(Linux,OS X等)将
long
作为64位类型。
然而,每个平台确实需要一个标准ABI。结构布局,甚至函数参数的解释都需要所有代码同意所使用的类型的大小。同一C编译器的不同版本的代码可以互操作,甚至遵循相同ABI的其他编译器也可以。 (但是,C++ ABI不够稳定,不能标准化。例如,g ++从未标准化过ABI,新版本确实会破坏ABI兼容性。)
请记住,C标准只告诉您可以在每个符合C实现中假定什么。 C标准还说,有符号整数可能是符号/大小,反码或二进制补码。任何特定平台都将使用硬件所使用的任何表示方式。
平台可以自由地标准化基本C标准未定义或实现定义的任何内容。例如,x86 C实现允许创建不对齐指针存在,甚至对它们进行解引用。这在
__m128i
矢量类型中经常发生。
实际选择的名称将WinAPI与其x86遗产联系起来,对于不熟悉x86汇编语言或至少Windows 16位DOS遗产的任何人来说,这是令人困惑的。
包括
w
表示字和
d
表示双字的8086指令助记符通常用作
idiv
有符号除法的设置。
这些指令在32位和64位模式下仍然存在并且执行相同的操作。(386和x86-64添加了扩展版本,如Intel的指令集参考中所示)。还有lodsw
, rep movsw
等字符串指令。
除了这些助记符外,在某些情况下需要显式指定操作数大小,例如:
mov dword ptr [mem], -1
,其中没有一个操作数是可以暗示操作数大小的寄存器。(要查看汇编语言的外观,只需反汇编一些内容。例如在Linux系统上,objdump -Mintel -d /bin/ls | less
)。
因此,在x86汇编中术语非常杂乱,这是你在开发ABI时需要熟悉的内容。
x86汇编背景、历史和当前命名方案
以下内容与WinAPI或原始问题无关,但我认为它很有趣。
请参见x86标签wiki,以获取Intel官方PDF的链接(以及其他好东西)。这种术语在Intel和AMD文档和指令助记符中仍然普遍存在,因为在一个使用一致性的特定架构的文件中,它完全不含糊。
386扩展了寄存器的大小到32位,并引入了cdq指令:cdq (eax (dword) -> edx:eax (qword))。(还引入了movsx和movzx,以在不需要将数据先加载到eax中的情况下进行符号或零扩展。)总之,quad-word是64位,即使在386之前也用于双精度内存操作数fld qword ptr [mem] / fst qword ptr [mem]。
英特尔仍然使用这种b/w/d/q/dq约定来命名向量指令,因此这绝不是他们试图淘汰的东西。例如,pshufd insn助记符 (_mm_shuffle_epi32 C intrinsic) 是Packed (integer) Shuffle Dword。psraw是Packed Shift Right Arithmetic Word。(FP向量insn使用ps (packed single)或pd (packed double)后缀而不是p前缀。)
随着向量变得越来越宽,命名开始变得愚蠢:例如,_mm_unpacklo_epi64是punpcklqdq指令的intrinsic:Packed-integer Unpack L Quad-words to Double-Quad。或movdqu用于Move Double-Quad Unaligned loads/stores(16字节)。一些汇编器使用o(oct-word)声明16字节整数常量,但英特尔助记符和文档始终使用dq。
为了保持我们的理智,AVX 256b (32B) 指令仍然使用SSE助记符,因此
vmovdqu ymm0, [rsi]
是一个32字节的加载,但没有四重术语。即使不含糊,包括操作数大小的反汇编器也会打印
vmovdqu ymm0, ymmword ptr [rsi]
。
一些AVX-512扩展名甚至使用b/w/d/q术语。AVX-512F(基础)并未包含每个指令的所有元素大小版本。某些指令的8位和16位元素大小版本仅在支持AVX-512BW扩展的硬件上可用。还有AVX-512DQ,用于额外的双字和四字元素大小指令,包括浮点/双精度和64位整数之间的转换以及一个乘法运算,其大小为64b x 64b => 64b。
一些新指令在助记符中使用数字大小。
AVX的
vinsertf128
等提取256位向量的高128位通常可以使用
dq
,但它使用
128
。
AVX-512引入了一些insn助记符,例如
vmovdqa64
(在64位元素粒度下进行掩码的向量加载)或
vshuff32x4
(以32位元素粒度进行混洗128b元素)。
请注意,由于AVX-512几乎所有指令都具有合并掩码或零掩码,即使以前不关心元素大小的指令(如
pxor
/
_mm_xor_si128
),现在也有不同的大小:
_mm512_mask_xor_epi64
(
vpxorq
)(每个掩码位影响一个64位元素),或
_mm512_mask_xor_epi32
(
vpxord
)。无掩码内在函数
_mm512_xor_si512
可以编译为
vpxorq
或
vpxord
;这没有关系。
大多数AVX512新指令在助记符中仍然使用b / w / d / q,例如VPERMT2D
(从两个源向量中选择元素的完整置换)。
short
类型的大小至少为 16 位,具体大小由实现决定。微软是这个实现者,并且他们选择了 16 位。 - Mysticialshort
始终是 16 位长,则在微软平台上,short
始终是 16 位长。这是他们的决定。 - EOFWORD
和DWORD
早于uint16_t
和uint32_t
。 - Weather VaneWORD
是16位的,但并没有说明short
的大小。 - Ajay