下面是我的一个测试过程,最初测试目标已达到,但又发现了相关问题,问题很小,但很严重,我会尽量写详细,所以看上去内容比较多。如若不想看那么多,请直接看结尾图片及其下内容。
我对于 IUnknown 定义中有个不明之处。
IUnknown struct DWORD
QueryInterface IUnknown_QueryInterface ?
AddRef IUnknown_AddRef ?
Release IUnknown_Release ?
IUnknown ends
struct 后面的 DWORD 是干嘛用的?
为此,我进行了这个测试。
我猜想,它可能的作用是:
* 让结构体中的元素以此对齐
* 让结构体大小为它的公倍数
设计一个结构体数组
struct {char a; int b; char c;} s[3];
清零后往结构体里填值,再按字节显示出来,
由此可以判断出其功效来。
结果:我发现其功能正是两个。
我尝试写了个 3,得出
>> error A2064: structure alignment must be 1, 2, 4, 8, or 16
相应可以用 byte word dword qword 等,但其缩写 db dw dd dq 却不支持。
不写,则默认为 1,即缺省值。
我还发现几个 Bug:
1. 实际上它只支持 1 2 4,不支持 8 16。
2. 当对齐非 1 时,它不能正确初始化数组,值不正确。
3. 当对数组中的多个元素(结构体)初始化后,数组元素个数不正确,最终字节数为
元素(结构体)长度 * 元素个数(dup值) * 用于初始化的元素个数。
这里它多乘了第三个因数。
以下为全部代码。程序运行后,会弹出对话框,对两个变量和六个数组逐字节,分行显示其十六进制值。
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 定义测试用的结构体
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HvDWORD struct DWORD
aa BYTE ?
bb DWORD ?
cc BYTE ?
HvDWORD ends
; HvDWORD 与 NoDWORD 的区别在于是否在 struct 关键字后加 DWORD
NoDWORD struct
aa BYTE ?
bb DWORD ?
cc BYTE ?
NoDWORD ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
hvdd0 HvDWORD <11h,22abcd22h,33h>
hvdd1 HvDWORD 1 dup (<11h,22abcd22h,33h>)
hvdd2 HvDWORD 2 dup (<11h,22abcd22h,33h>)
hvdd3 HvDWORD 3 dup (<11h,22abcd22h,33h>,<44h,55abcd55h,66h>,<77h,88abcd88h,99h>)
nodd0 NoDWORD <11h,22abcd22h,33h>
nodd1 NoDWORD 1 dup (<11h,22abcd22h,33h>)
nodd2 NoDWORD 2 dup (<11h,22abcd22h,33h>)
nodd3 NoDWORD 3 dup (<11h,22abcd22h,33h>,<44h,55abcd55h,66h>,<77h,88abcd88h,99h>)
; 就测试结果看,这里存在不少问题,参见说明。
szCaption db 'HEX',0
szFormatHex db '%02X ',0
szFormatEnd db '(%dB)',0ah,0ah,0
.data?
szText db 4000 dup (?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;--------------------------------------------------------------------
; @brief 将字节串打印为十六进制字符串
; @param _dst 目标字符串首址
; @param _src 源字节串首址
; @param _lng 源字节串长度
; @return 目标字符串尾址
printhex proc _dst,_src,_lng
local @lng
push _lng
pop @lng
.repeat
mov eax,_src
invoke wsprintf,_dst,offset szFormatHex,byte ptr [eax]
add _dst,eax
; 下一个
inc _src
dec @lng
.until @lng == 0
invoke wsprintf,_dst,offset szFormatEnd,_lng
add eax,_dst
ret
printhex endp
;--------------------------------------------------------------------
start:
lea eax,szText
invoke printhex,eax,offset hvdd0,sizeof hvdd0
invoke printhex,eax,offset hvdd1,sizeof hvdd1
invoke printhex,eax,offset hvdd2,sizeof hvdd2
invoke printhex,eax,offset hvdd3,sizeof hvdd3
invoke printhex,eax,offset nodd0,sizeof nodd0
invoke printhex,eax,offset nodd1,sizeof nodd1
invoke printhex,eax,offset nodd2,sizeof nodd2
invoke printhex,eax,offset nodd3,sizeof nodd3
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
对照图片,可以看出:
关于错误的归纳,我前面已提及。
hvdd0 HvDWORD <11h,22abcd22h,33h> ; 正确
hvdd1 HvDWORD 1 dup (<11h,22abcd22h,33h>) ; 错误,值不对
hvdd2 HvDWORD 2 dup (<11h,22abcd22h,33h>) ; 错误,值不对
hvdd3 HvDWORD 3 dup (<11h,22abcd22h,33h>,<44h,55abcd55h,66h>,<77h,88abcd88h,99h>) ; 错误,值和个数都不对
nodd0 NoDWORD <11h,22abcd22h,33h> ; 正确
nodd1 NoDWORD 1 dup (<11h,22abcd22h,33h>) ; 正确
nodd2 NoDWORD 2 dup (<11h,22abcd22h,33h>) ; 正确,但我以为后面的元素(结构体)应该全是0
nodd3 NoDWORD 3 dup (<11h,22abcd22h,33h>,<44h,55abcd55h,66h>,<77h,88abcd88h,99h>) ; 错误,个数不对
结构体数组初始化不正确,是编译器bug还是我的问题?
有没有办法达成如下的初始化?
struct __attribute__((__aligned__(4))) {
unsigned char aa;
unsigned long bb;
unsigned char cc;
} s[3] = {
{0x11, 0x22abcd22, 0x33},
{0x44, 0x55abcd55, 0x66},
{0x77, 0x88abcd88, 0x99}
};
以上。谢谢。
------解决思路----------------------
nodd3 个数不对?
ml.exe 6.14.8444 也是这样,生成的 lst 看着是对的,但obj 就是不对。而且,问题好像还不止于此,struc 语句的说明里说那个 dword 是数组元素对齐大小,和命令行里的 /Zp? 相似,所以就看了下 /Zp4 的结果,更是大出意外。
有这个问题,还是别跟它纠结了吧,确实需要就自己补了。
------解决思路----------------------
不加 /coff 即生成 OMF 格式的 obj 竟然是正确的。/coff 的问题看来是真多,上次有个定义巨量数据区(1024*1024 dd dup (0)) 耗时过多也是 /coff 时存在,OMF 时就不会。
------解决思路----------------------
我用ml 10.00.30319.01、ml 12.00.21005.1测试是没有问题的,见图:
------解决思路----------------------
#3 的也不对吧,按照通常的理解,最上面的两行应该一样的,毕竟只是直接定义和 1 dup <> 的区别。
------解决思路----------------------
我直接复制编译楼主的程序,输出就是这样。
我的理解,ml对
hvdd0 HvDWORD <11h,22abcd22h,33h>
hvdd1 HvDWORD 1 dup (<11h,22abcd22h,33h>)
的处理是不同的,二在意义上并不等价。
前者理解为hvdd0定义为HvDWORD类型<11h,22abcd22h,33h>
后者理解为hvdd1定义为HvDWORD 类型,填充数据字节11h,22abcd22h,33h,不足部分补0。
------解决思路----------------------
也不对,1 dup (<11h,22abcd22h,33h>)确实是复制了一个HvDWORD结构,数据为<11h,22abcd22h,33h>,但是没有处理对齐。
------解决思路----------------------
hvdd2 HvDWORD 2 dup (<11h,22abcd22h,33h>)
写成
hvdd2 HvDWORD <11h,22abcd22h,33h>, <11h,22abcd22h,33h>
就对了。
看来dup()中的结构忽略对齐,算是一个BUG吧,不过一直到VC++2013中的ml都没修正(我没装2015,不知道怎样),估计已经成为“特性”了。
------解决思路----------------------
masm可以测试高版本,不要用6.1x版本了。
或者楼主可以尝试一下yasm或nasm
------解决思路----------------------
对这些古怪的表现,感觉还是用 omf 格式的算了,最多定义成 start:: 全局并 public 之(或将其 proc 了),链接时指定入口并将相应的库再加上,因为 omf 不包含这些信息或是在被 link 转换为 coff 时丢了。
用其它的编译器,语法上要求可能不同,改动或许更大。
------解决思路----------------------
高版本link已经不支持omf格式的obj。