一个%0nX格式化输出引发的“血案”

本文通过一个PE文件解析器的实例,详细解释了在C/C++中使用%X格式符输出不同类型的变量时,如何根据变量的有符号或无符号特性进行正确地格式化输出。并介绍了在32位编译器环境下,%X、%lx和%llx格式符的默认输出宽度及扩展方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在写一个PE文件解析器的时候,大致写了这样一段代码:

这里写图片描述
本以为0X88没有超出%02X的格式限制。输出应该是88,殊不知输出的结果是FFFFFF88。正当我百思不得其解时,我修改了一下宏定义那句:

#define BYTE unsigned char

结果发现输出按照88正常输出。经过查找资料和反汇编分析,我得到了正确的结论,分析如下:

%X默认的输出宽度为整型的宽度,在32位编译器中即4字节。这点验证可查看反汇编(VC++6.0):定义时虽然是byte ptr [ebp-4]只占用栈中一个字节,但是在输出时要按照4字节输出,则先将其用movsx带符号扩展为四个字节再输出。而由于定义时是一个有符号数,那么88H即10001000,符号位为1,则补齐四字节时前面全部补全为1,带符号扩展得到FFFFFF88,输出也为FFFFFF88。
这里写图片描述
②当我将#define BYTE char修改为#define BYTE unsigned char时,虽然也是扩展,但由于是一个无符号数,符号位为0,前面全部补0即0X00000088,在以%02X输出时为88。反汇编如下(虽然没有用不带符号扩展指令,但是and eax,0XFF的效果是一样的,都将高为全部置为0):
这里写图片描述

总结:
%X默认按照int的宽度输出,%lx默认按照long的宽度输出(32位编译器下二者无差别);而%llx默认则是按照long long的宽度输出。
②不足默认宽度的会被宽展为指定宽度,并且扩展时依据符号进行扩展。
③%0NX,如果要输出值的字符个数大于N则“0N”的修饰无用,不要误认为输出的值占的字符个数和N有必然联系。
基础知识的细节很重要,但是调试技术的掌握更为重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值