【C】貌似不友好的scanf()

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

 以上。

原文地址:https://www.cnblogs.com/wxiaoli/p/5313417.html