在写Qt读PE文件的2进制编码时遇到,将PE文件读到QByteArray中,根据PE文件的e_lfanew,来定位PE文件标识“PE”。
QByteArray中存储一个字节为0x80,将QByteArray对象arr加下标强转为Int,得到的却是-128。
上恕问题简化来看:
第一次打印,用QByteArray强转了一下。
第二次打印,直接强转的0x80。
结果却是很神奇, 第一次是-128,第二次是128。
按常理来说,一个数据在内存中的存储不存在是不是带符号数据,而取决于你拿到这个数据后要解析成什么类型的数据来用。
问了一下同事,经过他反复尝试发现,先将arr[0]转成 unsigned char 再转成 int 。
结果这次非常神奇,竟然都是128了。为什么会发生这种情况呢?
难道数据转换之前,还有其他操作吗?
于是我将他们的二进制打印了出来。
发现如果如果arr[0]直接转int的话,前面会全部补1。
切换到宇宙第一IDE
先看将0x80存到char中,直接用int或上
结果负的128。查看代码反汇编
发现了一条操作 movsx
我们再看 0x80存放到 unsigned char ,再用int或上
运行结果正128。再看反汇编
发现,movsx 变成了movzx
这两条指令是什么意思呢,通过x86汇编指令手册描述
movsx 是将高位扩展成符号位
movzx 是将高位扩展成0
破案了,所以用char来强转int,如果符号位为1,就会将所有的高位全部补成1。
我们来调试一下看看
先将0x7F (二进制:0111 1111)符号位为0。看看movsx会怎么处理
先将7f放到c的栈区,再将c栈区的值也就是0x7F movsx 到eax寄存器
此时EAX寄存器的值为 0000007F。
再将0x80 (二进制:1000 0000)符号位为1。看看movsx会怎么处理
此时EAX寄存器的值为 FFFFFF80。
自此真相大白,所以当需要char 转 int的时候,还是先将char 转成 unsigned char后再转为int才比较保险。