我刚开始学习WinAPI。在MSDN中,为WORD数据类型提供了以下说明。
WORD
一个16位无符号整数。范围是0到65535十进制 此类型在WinDef.h中声明如下:
typedef unsigned short WORD;
很简单,它与我用于学习的其他资源相匹配,但它怎么能明确地说它是16位?维基百科上的C data types页面指定了
short / short int / signed short / signed short int
短符号整数 类型。
至少包含[-32767,+ 32767]范围;从而, 至少 16位大小。
因此根据C标准,short
的大小很可能是32位。但是谁决定使用什么比特尺寸呢?我在这里找到了practical explanation。具体来说,行:
......这取决于两个处理器(更具体地说,ISA,指令 设置架构,例如x86和x86-64)和编译器包括 编程模型。
所以这就是ISA,我认为这是有道理的。这是我迷路的地方。看一下维基百科上的Windows page,我在侧栏中看到了这一点:
平台 ARM,IA-32,Itanium,x86-64,DEC Alpha,MIPS,PowerPC
我真的不知道这些是什么,但我认为这些是处理器,每个处理器都有ISA。也许Windows支持这些平台,因为它们都保证为unsigned short
使用16位?这听起来不太对劲,但我对这些东西的了解还不够深入。
回到我的问题:当C标准本身不保证{{1}时,Windows API如何typedef unsigned short WORD;
然后说WORD
是一个16位无符号整数是怎么回事?总是16位?
答案 0 :(得分:9)
简单地说,WORD
总是16位。
由于WORD
始终为16位,但unsigned short
不是WORD
,unsigned short
并非始终为#ifdef
。
对于Windows SDK支持的每个平台,Windows头文件包含WORD
样式宏,可以检测编译器及其平台,并关联Windows SDK定义的类型(DWORD
,{{1等等适当大小的平台类型。
这就是为什么Windows SDK实际上使用内部定义的类型,例如WORD
,而不是使用语言类型:这样他们就可以确保它们的定义始终是正确的。
Microsoft工具链附带的Windows SDK可能很懒,因为Microsoft c ++工具链总是使用16位无符号短路。
我不希望Visual Studio C ++附带的windows.h能够正常工作,如果放入GCC,铿锵等等很多细节,包括使用平台导入dll的机制.iib文件SDK分发,是Microsoft特定的实现。
不同的解释是:
微软称WORD
为16位。如果"某人"想要调用Windows API,它们必须传递16位值,其中API将字段定义为WORD。
微软也可能会说,为了构建一个有效的Windows程序,使用Windows SDK中的Windows头文件,用户必须选择一个16bit short
的编译器。
c ++规范没有说编译器必须将short
实现为16位 - 微软说你选择构建windows可执行文件的编译器必须。
答案 1 :(得分:7)
最初假设所有打算在Windows上运行的代码都将使用Microsoft自己的编译器 - 或完全兼容的编译器进行编译。这就是它的工作方式。 Borland C:匹配Microsoft C. Zortech的C:匹配Microsoft C. gcc:不是那么多,所以你甚至没有尝试(更不用说没有运行时等)。
随着时间的推移,这个概念被编纂并扩展到其他操作系统(或者可能是其他操作系统首先获得它),现在它被称为ABI - Application Binary Interface - 用于平台,所有编译器假设(在实践中,需要)该平台以匹配ABI。这意味着匹配对整数类型(以及其他)的大小的期望。
你没有问过一个有趣的相关问题是:那么为什么16位称为字?为什么在32-和现在的64位架构上32位是 dword (双字),本机“字”大小是32或64-而不是16?因为:80286。
答案 2 :(得分:2)
在windows标题中有很多基于平台的#define可以确保WORD是16位,DWORD是32等等。在过去的某些情况下,我知道他们为每个平台分配了一个合适的SDK 。在任何情况下都没有什么神奇之处,只需要合适的#defines和标题。
答案 3 :(得分:1)
BYTE=8bits
,WORD=16bits
和DWORD=32bits
(双字)术语来自英特尔8086的指令助记符和文档。它只是术语,并且在这一点上并不意味着在运行代码的实际机器上有the size of the "machine word"的任何内容。
我的猜测:
最初引入这些C类型名称的原因与C99 standardized uint8_t
, uint16_t
, and uint32_t
相同。这个想法可能是允许使用不兼容的ABI(例如16位int
或32位short
)的C实现仍然编译使用WinAPI的代码,因为ABI使用DWORD
而不是{{ {}}中的1}}或long
,以及函数args /返回值。
可能随着Windows的发展,足够多的代码开始依赖于MS决定standardize the exact typedef
s的WORD和DWORD的确切定义。这与C99 int
想法不同,您不能认为它是struct
。
作为@supercat points out,这对于别名规则很重要。例如如果您通过uint16_t
修改unsigned short
数组,则可以保证它将按预期工作。但是,如果通过unsigned long[]
修改DWORD*
的数组,编译器可能会认为它不会影响它在寄存器中已有的数组值。这对unsigned int[]
格式字符串也很重要。 (C99' DWORD*
解决方法是preprocessor macros like PRIu32
。)
或许这个想法只是使用与asm相匹配的名称,以确保没有人对类型的宽度感到困惑。在Windows的早期阶段,直接用asm而不是C编写程序很受欢迎。 WORD / DWORD使得以asm编写的人员的文档更加清晰。
或许这个想法只是为便携式代码提供固定宽度类型。例如printf
:将其定义为该平台的适当类型。正如你所注意到的那样,这就是它的好处:
Windows API如何键入unsde unsigned short WORD;当C标准本身不能保证短路总是16位时,WORD是一个16位无符号整数?
您正确,记录确切的<stdint.h>
表示无法在使用其他ABI的系统中正确实施WinAPI标头(例如,#ifdef SUNOS
是64位或typedef
是32位)。这是x86-64 Windows ABI使long
成为32位类型的部分原因。 x86-64 System V ABI(Linux,OS X等)使short
成为64位类型。
每个平台都需要标准的ABI,但。 long
布局,甚至函数args的解释,要求所有代码都同意所用类型的大小。来自不同版本的相同C编译器的代码可以互操作,甚至其他编译器也遵循相同的ABI。 (但是,C ++ ABI不够稳定,无法标准化。例如,long
从未标准化ABI,新版本确实打破了ABI兼容性。)
请记住,C标准只告诉您在每个符合C的实现中可以采用的内容。 C标准还说有符号整数可能是符号/幅度,补码,或两个补码。但是,任何特定平台都将使用硬件所做的任何表示。
平台可以自由地标准化基本C标准未定义或实现定义的任何内容。例如x86 C实现允许创建存在的未对齐指针,甚至可以取消引用它们。这种情况在struct
向量类型中发生了很多。
选择的实际名称将WinAPI与其x86传统联系起来,不幸的是,对于不熟悉x86 asm,或者至少是Windows的16位DOS遗产的人来说,这会让人感到困惑。
包含g++
for word和__m128i
for dword的8086指令助记符通常用作idiv
signed division的设置。
cbw
: sign extend AL (byte) into AX (word) cwd
: sign extend AX (word) into DX:AX (dword),即将w
的符号位复制到d
的每一位。这些insn仍然存在并且在32位和64位模式下完全相同。 (386和x86-64增加了扩展版本,正如您在英特尔的insn集参考文献中所看到的那样。)还有lodsw
,ax
等字符串指令
除了那些助记符之外,在某些情况下需要明确指定操作数大小,例如
dx
,其中操作数都不是可以暗示操作数大小的寄存器。 (要查看汇编语言是什么样的,只需反汇编某些东西。例如在Linux系统上rep movsw
。)
所以这个术语在x86 asm中到处都是,developing an ABI时你需要熟悉这个术语。
这一点下面的任何内容都与WinAPI或原始问题无关,但我认为这很有趣。
另请参阅x86代码Wiki,以获取英特尔官方PDF(以及许多其他好东西)的链接。这个术语在英特尔和AMD的文档和指令助记符中仍然无处不在,因为它在特定体系结构的文档中完全明确,并且始终如一地使用它。
386扩展寄存器大小为32位,并引入了mov dword ptr [mem], -1
指令:objdump -Mintel -d /bin/ls | less
(eax(dword) - &gt; edx:eax(qword))。 (还引入了cdq
和cdq
,无需首先将数据导入movsx
即可进行符号或零扩展。)无论如何,四字是64位,甚至使用在386之前的movzx
- fld qword ptr [mem]
/ eax
的精确内存操作数。
英特尔仍然使用此b / w / d / q / dq约定进行矢量指令命名,因此它根本不是他们试图逐步淘汰的东西。< / p>
e.g。 pshufd
insn助记符(_mm_shuffle_epi32
C intrinsic)是Packed(整数)Shuffle Dword。 double
是Packed Shift Right算术字。 (FP vector insns使用fst qword ptr [mem]
(打包单个)或psraw
(打包双)后缀而不是ps
前缀。)
随着矢量变得越来越宽,命名开始变得愚蠢:例如_mm_unpacklo_epi64
is the intrinsic的punpcklqdq
instruction:打包整数解包L四字到双四元组。 (即将64位低半部分交织成一个128b)。或pd
用于移动双四元未对齐加载/存储(16字节)。一些汇编程序使用p
(oct-word)来声明16字节整数常量,但英特尔助记符和文档始终使用movdqu
。
幸运的是,为了我们的理智,AVX 256b(32B)指令仍然使用SSE助记符,因此o
是32B负载,但是没有四元组术语。包含操作数大小的反汇编程序,即使它不含糊也会打印dq
。
即使某些AVX-512扩展名的名称也使用b / w / d / q术语。 AVX-512F(基础)不包括每条指令的所有元素大小版本。某些指令的8位和16位元素大小版本仅适用于supports the AVX-512BW扩展的硬件。对于额外的双字和qword元素大小指令,还有 AVX-512DQ ,包括float / double和64bit整数与a multiply with 64b x 64b => 64b element size之间的转换。
AVX's vinsertf128
类似用vmovdqu ymm0, [rsi]
,而是使用vmovdqu ymm0, ymmword ptr [rsi]
。
AVX-512引入了一些名称为dq
的insn助记符(带有64位元素粒度掩码的向量加载)或128
(随机播放128b元素,屏蔽为32位元素粒度)。
请注意,由于AVX-512几乎对所有指令都具有合并屏蔽或零屏蔽功能,因此即使用于关注元素大小的指令也是如此(例如vmovdqa64
/ vshuff32x4
)现在有不同的大小:_mm512_mask_xor_epi64
(vpxorq
)(每个掩码位影响64位元素)或pxor
(_mm_xor_si128
)。无掩码内在_mm512_mask_xor_epi32
可以编译为vpxord
或_mm512_xor_si512
;没关系。
大多数AVX512新指令在其助记符中仍然使用b / w / d / q,例如vpxorq
(从两个源向量中选择完全置换元素)。
答案 4 :(得分:0)
目前没有支持Windows API的平台,但{16}没有unsigned short
。
如果有人制作了这样的平台,该平台的Windows API标头将不包含该行typedef unsigned short WORD;
。
您可以将MSDN页面视为描述x86 / x64平台上MSVC ++的典型行为。
答案 5 :(得分:0)
像WORD这样的类型的遗留问题早于Windows遵循由MASM定义的类型(后来名称更改为ML)的MSDOS时代。 Windows API未采用MASM的签名类型,例如SBYTE,SWORD,SDWORD,SQWORD。
MASM中的QWORD / SQWORD可能没有定义,直到MASM / ML支持80386.当前参考:
http://msdn.microsoft.com/en-us/library/8t163bt0.aspx
Windows添加了类型,例如HANDLE,WCHAR,TCHAR,....
对于Windows / Microsoft编译器,size_t是一个与poitner大小相同的无符号整数,32位(如果是32位模式),64位(如果是64位模式)。
MASM中的DB和DW数据指令可以追溯到英特尔8080汇编程序的时代。