微软如何说WinAPI中单词的大小是16位?

时间:2016-05-18 19:23:31

标签: c windows winapi assembly msdn

我刚开始学习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位?

6 个答案:

答案 0 :(得分:9)

简单地说,WORD总是16位。

由于WORD始终为16位,但unsigned short不是WORDunsigned 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=8bitsWORD=16bitsDWORD=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 typedefs的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的设置。

这些insn仍然存在并且在32位和64位模式下完全相同。 (386和x86-64增加了扩展版本,正如您在英特尔的insn集参考文献中所看到的那样。)还有lodswax等字符串指令

除了那些助记符之外,在某些情况下需要明确指定操作数大小,例如
dx,其中操作数都不是可以暗示操作数大小的寄存器。 (要查看汇编语言是什么样的,只需反汇编某些东西。例如在Linux系统上rep movsw。)

所以这个术语在x86 asm中到处都是,developing an ABI时你需要熟悉这个术语。

更多x86 asm背景,历史和当前命名方案

这一点下面的任何内容都与WinAPI或原始问题无关,但我认为这很有趣。

另请参阅代码Wiki,以获取英特尔官方PDF(以及许多其他好东西)的链接。这个术语在英特尔和AMD的文档和指令助记符中仍然无处不在,因为它在特定体系结构的文档中完全明确,并且始终如一地使用它。

386扩展寄存器大小为32位,并引入了mov dword ptr [mem], -1指令:objdump -Mintel -d /bin/ls | less(eax(dword) - &gt; edx:eax(qword))。 (还引入了cdqcdq,无需首先将数据导入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 intrinsicpunpcklqdq 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之间的转换。

一些新指令在助记符

中使用数字大小 用于提取256位向量的高128位通道的

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汇编程序的时代。