scanf语句执行过程:
(1)逆序取参数的偏移地址并分别入栈。
(2)根据控制字符串的格式说明符从缓冲区取数据给各变量赋值。
①若格式说明符是数值类数据:如果从缓冲区中拿出的第一个字符可以合法表示该数值类型数据(如对应%d的可以是任何数字字符、+、-;若对应%x,则除了以上还有字母a—b也可,and so forth...),然后取下一个字符,直到非合法字符,则认为该数值读取完毕并把该非法字符送回缓冲区。把之前取得的合法字符串转换成相应的数值类型并赋值。
如果从缓冲区中拿出的第一个字符对应格式说明符来说不是合法字符则直接把该非法字符送回缓冲区,在不给当前变量赋值的情况下结束该条语句。如:
1 #include<stdio.h> 2 int main ( ) 3 { 4 int a,i=0; 5 printf("%d ",a); 6 while(i<5) 7 {scanf("%d",&a); 8 printf("%d ",a); 9 i++; 10 } 11 return 0; 12 }
程序执行如下图(其中第2行的a为输入回显)
②若格式说明符是c%则对所有输入内容都认为是合法并给变量赋值。
③若格式说明符是s%,则从第一个非空白字符开始认为合法字符直到遇到空白字符。
VC6.0反汇编结果(可以看出scanf函数取参数表中取地址的顺序与printf相同,都是倒着。)
1 1: #include<stdio.h> 2 2: int main (void) 3 3: { 4 00401010 push ebp 5 00401011 mov ebp,esp 6 00401013 sub esp,50h 7 00401016 push ebx 8 00401017 push esi 9 00401018 push edi 10 00401019 lea edi,[ebp-50h] 11 0040101C mov ecx,14h 12 00401021 mov eax,0CCCCCCCCh 13 00401026 rep stos dword ptr [edi] 14 4: int i=0; 15 00401028 mov dword ptr [ebp-4],0 16 5: char a,b,c; 17 6: printf("%c ",a); 18 0040102F movsx eax,byte ptr [ebp-8] 19 00401033 push eax 20 00401034 push offset string "%c " (00425fa4) 21 00401039 call printf (00401100) 22 0040103E add esp,8 23 7: while(i<5) 24 00401041 cmp dword ptr [ebp-4],5 25 00401045 jge main+77h (00401087) 26 8: {scanf("%c%c%c",&a,&b,&c); 27 00401047 lea ecx,[ebp-10h];取变量c的偏移地址 28 0040104A push ecx 29 0040104B lea edx,[ebp-0Ch];取变量b的偏移地址 30 0040104E push edx 31 0040104F lea eax,[ebp-8] ;取变量a的偏移地址 32 00401052 push eax 33 00401053 push offset string "%c" (0042501c) 34 00401058 call scanf (004010a0) 35 0040105D add esp,10h 36 9: printf("%c%c%c ",a,b,c); 37 00401060 movsx ecx,byte ptr [ebp-10h] 38 00401064 push ecx 39 00401065 movsx edx,byte ptr [ebp-0Ch] 40 00401069 push edx 41 0040106A movsx eax,byte ptr [ebp-8] 42 0040106E push eax 43 0040106F push offset string "%c%c%c " (00426000) 44 00401074 call printf (00401100) 45 00401079 add esp,10h 46 10: i++; 47 0040107C mov ecx,dword ptr [ebp-4] 48 0040107F add ecx,1 49 00401082 mov dword ptr [ebp-4],ecx 50 11: } 51 00401085 jmp main+31h (00401041) 52 12: return 0; 53 00401087 xor eax,eax 54 13: } 55 00401089 pop edi 56 0040108A pop esi 57 0040108B pop ebx 58 0040108C add esp,50h 59 0040108F cmp ebp,esp 60 00401091 call __chkesp (00401180) 61 00401096 mov esp,ebp 62 00401098 pop ebp 63 00401099 ret
以上。