今天写代码的时候发现一个有趣的问题,fscanf读入一个缓冲区的数据总是不完全,小生先把问题的简化代码贴一下
#include <stdio.h>
#include <windows.h>
void main()
{
char pwd[1024]={0};
FILE *fp=fopen("D:\\test\\1.txt", "rw+");
fscanf(fp, "%s", pwd);
printf("%s",pwd);
}
(
接一个插曲,这段代码放在vs2012中运行会出现如下错误
2012不支持w方式??
)
回到正文,1.txt内容如下:
在printf处下断,看下缓冲区pwd的内存
看到fscanf读到0x0e处就终止了,而文件的内容没有读完,起初我遇到这样的问题,最终定位在文件里的0x0a,后来测试一下从0d就读不进去了。我用od跟了一下,定位到从文件指针缓冲区复制数据到自定义缓冲区的代码
00405DBE |> /83BD 18FEFFFF>|/CMP DWORD PTR SS:[EBP-1E8],0
00405DC5 |. |74 14 ||JE SHORT 1.00405DDB
00405DC7 |. |8B45 E4 ||MOV EAX,DWORD PTR SS:[EBP-1C]
00405DCA |. |8B4D E4 ||MOV ECX,DWORD PTR SS:[EBP-1C]
00405DCD |. |83E9 01 ||SUB ECX,1
00405DD0 |. |894D E4 ||MOV DWORD PTR SS:[EBP-1C],ECX
00405DD3 |. |85C0 ||TEST EAX,EAX
00405DD5 |. |0F84 2A010000 ||JE 1.00405F05
00405DDB |> |8B55 E0 ||MOV EDX,DWORD PTR SS:[EBP-20] ; 堆栈 SS:[0012FAC8]=00000001
00405DDE |. |83C2 01 ||ADD EDX,1 ; 2
00405DE1 |. |8955 E0 ||MOV DWORD PTR SS:[EBP-20],EDX ; 12fac8
00405DE4 |. |8B45 08 ||MOV EAX,DWORD PTR SS:[EBP+8]
00405DE7 |. |50 ||PUSH EAX ; /Arg1
00405DE8 |. |E8 A30D0000 ||CALL 1.00406B90 ; \1.00406B90
00405DED |. |83C4 04 ||ADD ESP,4 ; 33
00405DF0 |. |8985 28FEFFFF ||MOV DWORD PTR SS:[EBP-1D8],EAX
00405DF6 |. |83BD 28FEFFFF>||CMP DWORD PTR SS:[EBP-1D8],-1
00405DFD |. |0F84 DF000000 ||JE 1.00405EE2
00405E03 |. |8B8D 28FEFFFF ||MOV ECX,DWORD PTR SS:[EBP-1D8]
00405E09 |. |C1F9 03 ||SAR ECX,3 ; 1f-0
00405E0C |. |0FBE540D A0 ||MOVSX EDX,BYTE PTR SS:[EBP+ECX-60] ; 堆栈 SS:[0012FA8E]=00; ebp-41, ebp-60
00405E11 |. |0FBE45 F0 ||MOVSX EAX,BYTE PTR SS:[EBP-10] ; 堆栈 SS:[0012FAD8]=FF
00405E15 |. |33D0 ||XOR EDX,EAX
00405E17 |. |8B8D 28FEFFFF ||MOV ECX,DWORD PTR SS:[EBP-1D8] ; 堆栈 SS:[0012F910]=00000033
00405E1D |. |83E1 07 ||AND ECX,7 ; 3
00405E20 |. |B8 01000000 ||MOV EAX,1
00405E25 |. |D3E0 ||SHL EAX,CL ; 8
00405E27 |. |23D0 ||AND EDX,EAX ; 8
00405E29 |. |85D2 ||TEST EDX,EDX
00405E2B |. |0F84 B1000000 ||JE 1.00405EE2
00405E31 |. |0FBE4D 90 ||MOVSX ECX,BYTE PTR SS:[EBP-70] ; 堆栈 SS:[0012FA78]=00
00405E35 |. |85C9 ||TEST ECX,ECX
00405E37 |. |0F85 94000000 ||JNZ 1.00405ED1
00405E3D |. |0FBE55 9C ||MOVSX EDX,BYTE PTR SS:[EBP-64] ; 堆栈 SS:[0012FA84]=00
00405E41 |. |85D2 ||TEST EDX,EDX
00405E43 |. |74 76 ||JE SHORT 1.00405EBB
00405E45 |. |8A85 28FEFFFF ||MOV AL,BYTE PTR SS:[EBP-1D8]
00405E4B |. |8885 10FEFFFF ||MOV BYTE PTR SS:[EBP-1F0],AL
00405E51 |. |8B8D 28FEFFFF ||MOV ECX,DWORD PTR SS:[EBP-1D8]
00405E57 |. |81E1 FF000000 ||AND ECX,0FF
00405E5D |. |8B15 90AE4200 ||MOV EDX,DWORD PTR DS:[42AE90] ; 1.0042AE9A
00405E63 |. |33C0 ||XOR EAX,EAX
00405E65 |. |66:8B044A ||MOV AX,WORD PTR DS:[EDX+ECX*2]
00405E69 |. |25 00800000 ||AND EAX,8000
00405E6E |. |85C0 ||TEST EAX,EAX
00405E70 |. |74 1B ||JE SHORT 1.00405E8D
00405E72 |. |8B4D E0 ||MOV ECX,DWORD PTR SS:[EBP-20]
00405E75 |. |83C1 01 ||ADD ECX,1
00405E78 |. |894D E0 ||MOV DWORD PTR SS:[EBP-20],ECX
00405E7B |. |8B55 08 ||MOV EDX,DWORD PTR SS:[EBP+8]
00405E7E |. |52 ||PUSH EDX ; /Arg1
00405E7F |. |E8 0C0D0000 ||CALL 1.00406B90 ; \1.00406B90
00405E84 |. |83C4 04 ||ADD ESP,4
00405E87 |. |8885 11FEFFFF ||MOV BYTE PTR SS:[EBP-1EF],AL
00405E8D |> |A1 9CB04200 ||MOV EAX,DWORD PTR DS:[42B09C]
00405E92 |. |50 ||PUSH EAX ; /Arg3 => 00000001
00405E93 |. |8D8D 10FEFFFF ||LEA ECX,DWORD PTR SS:[EBP-1F0] ; |
00405E99 |. |51 ||PUSH ECX ; |Arg2
00405E9A |. |8D55 FC ||LEA EDX,DWORD PTR SS:[EBP-4] ; |
00405E9D |. |52 ||PUSH EDX ; |Arg1
00405E9E |. |E8 BD780000 ||CALL 1.0040D760 ; \1.0040D760
00405EA3 |. |83C4 0C ||ADD ESP,0C
00405EA6 |. |8B45 C4 ||MOV EAX,DWORD PTR SS:[EBP-3C]
00405EA9 |. |66:8B4D FC ||MOV CX,WORD PTR SS:[EBP-4]
00405EAD |. |66:8908 ||MOV WORD PTR DS:[EAX],CX
00405EB0 |. |8B55 C4 ||MOV EDX,DWORD PTR SS:[EBP-3C]
00405EB3 |. |83C2 02 ||ADD EDX,2
00405EB6 |. |8955 C4 ||MOV DWORD PTR SS:[EBP-3C],EDX
00405EB9 |. |EB 14 ||JMP SHORT 1.00405ECF
00405EBB |> |8B45 C4 ||MOV EAX,DWORD PTR SS:[EBP-3C] ; 堆栈 SS:[0012FAAC]=0012FB75
00405EBE |. |8A8D 28FEFFFF ||MOV CL,BYTE PTR SS:[EBP-1D8] ; 堆栈 SS:[0012F910]=33 ('3')
00405EC4 |. |8808 ||MOV BYTE PTR DS:[EAX],CL ; CL=33 ('3')
00405EC6 |. |8B55 C4 ||MOV EDX,DWORD PTR SS:[EBP-3C]
00405EC9 |. |83C2 01 ||ADD EDX,1
00405ECC |. |8955 C4 ||MOV DWORD PTR SS:[EBP-3C],EDX
00405ECF |> |EB 0F ||JMP SHORT 1.00405EE0
00405ED1 |> |8B85 1CFEFFFF ||MOV EAX,DWORD PTR SS:[EBP-1E4]
00405ED7 |. |83C0 01 ||ADD EAX,1
00405EDA |. |8985 1CFEFFFF ||MOV DWORD PTR SS:[EBP-1E4],EAX
00405EE0 |> |EB 1E ||JMP SHORT 1.00405F00
00405EE2 |> |8B4D E0 ||MOV ECX,DWORD PTR SS:[EBP-20]
00405EE5 |. |83E9 01 ||SUB ECX,1
00405EE8 |. |894D E0 ||MOV DWORD PTR SS:[EBP-20],ECX
00405EEB |. |8B55 08 ||MOV EDX,DWORD PTR SS:[EBP+8]
00405EEE |. |52 ||PUSH EDX ; /Arg2
00405EEF |. |8B85 28FEFFFF ||MOV EAX,DWORD PTR SS:[EBP-1D8] ; |
00405EF5 |. |50 ||PUSH EAX ; |Arg1
00405EF6 |. |E8 F50C0000 ||CALL 1.00406BF0 ; \1.00406BF0
00405EFB |. |83C4 08 ||ADD ESP,8
00405EFE |. |EB 05 ||JMP SHORT 1.00405F05
00405F00 |>^\E9 B9FEFFFF |\JMP 1.00405DBE
0x00405de8处的call是从文件中读取一个字节放到eax中,
0x00405df6判断是否读到文件结束,
从00405E03 到00405E2B 的代码致使这个问题的出现,解释下这段
EBP-1D8中存放从文件中读取的一个字节,然后右移3位,这里不难分析ecx的取值范围0~1f,
往下405e0c处代码,分析这一句ebp+ecx-60的范围应该在ebp-41到ebp-60,看下内存:
选中部分有两处值不为0,而当EBP-1D8中的值为0x0a或者0x0d这样时则ebp+ecx-60命中0x3e,
0x00405E11处代码ebp-10取值始终为0xff。将ebp+ecx-60 与ebp-10的值xor存于edx,再将读取的一个字节与7进行and存放在ecx,(讲的可能有点乱,还5行直接贴代码吧)
00405E1D |. 83E1 07 ||AND ECX,7 ; 3
00405E20 |. B8 01000000 ||MOV EAX,1
00405E25 |. D3E0 ||SHL EAX,CL ; 8
00405E27 |. 23D0 ||AND EDX,EAX ; 8
00405E29 |. 85D2 ||TEST EDX,EDX
00405E2B |. 0F84 B1000000 ||JE 1.00405EE2
当读入字节为0x0a时,0x00405E2b处跳转实现,和上面判断为文件结束跳向同一地址。。
如果我们有需要fscanf 0x0a这样的字节岂不是scanf不进去了?
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!