C函數(shù)調(diào)用而忘記參數(shù)列表的后果 [C專家編程]

故事從C專家編程的第三章分析C語言的聲明開始,書中給出了cdecl代碼,正好昨天把整章看完,所以今天就想著把程序抄一邊,然后搞懂一下怎么回事。代碼可以參考此鏈接。

這兒只將涉及到我的問題的部分代碼摘錄下來,原始代碼:

void deal_with_declarator()  
{  
    /*處理標(biāo)識符之后可能存在的數(shù)組/函數(shù)*/  
    switch(this.type)  
    {  
        case '[':  
            deal_with_arrays();  
                 break;  
        case '(':  
                 deal_with_function_args();  
                 break;  
    }  
    deal_with_pointers();  
    /*處理在讀入到標(biāo)識符之前壓入到堆棧的符號*/  
    while(top>=0)  
    {  
        if(stack[top].type=='('){  
            pop;  
            gettoken();/*讀取')'之后的符號*/  
            deal_with_declarator();  
        }  
        else  
        {  
            printf("%s ",pop.string);  
        }  
    }  
}  
int main()  
{  
    /*將標(biāo)記壓入堆棧中,直到遇見標(biāo)識符*/  
    read_to_first_identifier();  
    deal_with_declarator();  
    printf("\n");  
    return 0;  
}  

而我在抄的時候?qū)?code>deal_with_declarator函數(shù)內(nèi)部的一個函數(shù)調(diào)用忘記了()

        if(stack[top].type=='('){  
            pop;  
            gettoken;  //問題正出在這兒,雖然沒有括號,但依然能編譯通過
            deal_with_declarator();  
        }  

我們先看一下,原始代碼編譯后是什么樣的,記住加上-g選項:

(gdb) disassemble /m deal_with_declarator 
Dump of assembler code for function deal_with_declarator:
109 void deal_with_declarator(void) {
   0x08048a0e <+0>: push   %ebp
   0x08048a0f <+1>: mov    %esp,%ebp
   0x08048a11 <+3>: sub    $0x8,%esp

110     //printf("\nthis.type %c\n",this.type);
111     switch(this.type) 
   0x08048a14 <+6>: movzbl 0x804a060,%eax
   0x08048a1b <+13>:    movsbl %al,%eax
   0x08048a1e <+16>:    cmp    $0x28,%eax
   0x08048a21 <+19>:    je     0x8048a2f <deal_with_declarator+33>
   0x08048a23 <+21>:    cmp    $0x5b,%eax
   0x08048a26 <+24>:    jne    0x8048a34 <deal_with_declarator+38>

112     {
113         case '[' : 
114             deal_with_arrays(); break;
   0x08048a28 <+26>:    call   0x80488fb <deal_with_arrays>
   0x08048a2d <+31>:    jmp    0x8048a34 <deal_with_declarator+38>

115         case '(' : 
116             deal_with_function_args(); break;
   0x08048a2f <+33>:    call   0x804898c <deal_with_function_args>

117     }
118     deal_with_pointers();
   0x08048a34 <+38>:    call   0x80489bc <deal_with_pointers>

119 
120     while( top >= 0 ){
   0x08048a39 <+43>:    jmp    0x8048a9b <deal_with_declarator+141>
   0x08048a9b <+141>:   mov    0x804a038,%eax
   0x08048aa0 <+146>:   test   %eax,%eax
   0x08048aa2 <+148>:   jns    0x8048a3b <deal_with_declarator+45>

121         if( stack[top].type == '(') {
   0x08048a3b <+45>:    mov    0x804a038,%edx
   0x08048a41 <+51>:    mov    %edx,%eax
   0x08048a43 <+53>:    shl    $0x6,%eax
   0x08048a46 <+56>:    add    %edx,%eax
   0x08048a48 <+58>:    add    $0x804a0c0,%eax
   0x08048a4d <+63>:    movzbl (%eax),%eax
   0x08048a50 <+66>:    cmp    $0x28,%al
   0x08048a52 <+68>:    jne    0x8048a6d <deal_with_declarator+95>

122             pop;
---Type <return> to continue, or q <return> to quit---
   0x08048a54 <+70>:    mov    0x804a038,%eax
   0x08048a59 <+75>:    sub    $0x1,%eax
   0x08048a5c <+78>:    mov    %eax,0x804a038

123             gettoken();
   0x08048a61 <+83>:    call   0x8048774 <gettoken>  #函數(shù)調(diào)用

124             deal_with_declarator();
   0x08048a66 <+88>:    call   0x8048a0e <deal_with_declarator>
   0x08048a6b <+93>:    jmp    0x8048a9b <deal_with_declarator+141>

125         }else {
126             printf("%s ", pop.string);
   0x08048a6d <+95>:    mov    0x804a038,%edx
   0x08048a73 <+101>:   lea    -0x1(%edx),%eax
   0x08048a76 <+104>:   mov    %eax,0x804a038
   0x08048a7b <+109>:   mov    %edx,%eax
   0x08048a7d <+111>:   shl    $0x6,%eax
   0x08048a80 <+114>:   add    %edx,%eax
   0x08048a82 <+116>:   add    $0x804a0c0,%eax
   0x08048a87 <+121>:   add    $0x1,%eax
   0x08048a8a <+124>:   sub    $0x8,%esp
   0x08048a8d <+127>:   push   %eax
   0x08048a8e <+128>:   push   $0x8048be4
   0x08048a93 <+133>:   call   0x8048410 <printf@plt>
   0x08048a98 <+138>:   add    $0x10,%esp

127         }
128     }
129 }
   0x08048aa4 <+150>:   nop
   0x08048aa5 <+151>:   leave  
   0x08048aa6 <+152>:   ret    

End of assembler dump.

其中第123行是調(diào)用函數(shù)gettoken。

我們再看看錯誤代碼的匯編結(jié)果:

(gdb) disassemble /m deal_with_declarator 
Dump of assembler code for function deal_with_declarator:
109 void deal_with_declarator(void) {
   0x08048a0e <+0>: push   %ebp
   0x08048a0f <+1>: mov    %esp,%ebp
   0x08048a11 <+3>: sub    $0x8,%esp

110     //printf("\nthis.type %c\n",this.type);
111     switch(this.type) 
   0x08048a14 <+6>: movzbl 0x804a060,%eax
   0x08048a1b <+13>:    movsbl %al,%eax
   0x08048a1e <+16>:    cmp    $0x28,%eax
   0x08048a21 <+19>:    je     0x8048a2f <deal_with_declarator+33>
   0x08048a23 <+21>:    cmp    $0x5b,%eax
   0x08048a26 <+24>:    jne    0x8048a34 <deal_with_declarator+38>

112     {
113         case '[' : 
114             deal_with_arrays(); break;
   0x08048a28 <+26>:    call   0x80488fb <deal_with_arrays>
   0x08048a2d <+31>:    jmp    0x8048a34 <deal_with_declarator+38>

115         case '(' : 
116             deal_with_function_args(); break;
   0x08048a2f <+33>:    call   0x804898c <deal_with_function_args>

117     }
118     deal_with_pointers();
   0x08048a34 <+38>:    call   0x80489bc <deal_with_pointers>

119 
120     while( top >= 0 ){
   0x08048a39 <+43>:    jmp    0x8048a96 <deal_with_declarator+136>
   0x08048a96 <+136>:   mov    0x804a038,%eax
   0x08048a9b <+141>:   test   %eax,%eax
   0x08048a9d <+143>:   jns    0x8048a3b <deal_with_declarator+45>

121         if( stack[top].type == '(') {
   0x08048a3b <+45>:    mov    0x804a038,%edx
   0x08048a41 <+51>:    mov    %edx,%eax
   0x08048a43 <+53>:    shl    $0x6,%eax
   0x08048a46 <+56>:    add    %edx,%eax
   0x08048a48 <+58>:    add    $0x804a0c0,%eax
   0x08048a4d <+63>:    movzbl (%eax),%eax
   0x08048a50 <+66>:    cmp    $0x28,%al
   0x08048a52 <+68>:    jne    0x8048a68 <deal_with_declarator+90>

122             pop;
---Type <return> to continue, or q <return> to quit---
   0x08048a54 <+70>:    mov    0x804a038,%eax
   0x08048a59 <+75>:    sub    $0x1,%eax
   0x08048a5c <+78>:    mov    %eax,0x804a038

123             gettoken;   #看到?jīng)],啥也沒做
124             deal_with_declarator();
   0x08048a61 <+83>:    call   0x8048a0e <deal_with_declarator>
   0x08048a66 <+88>:    jmp    0x8048a96 <deal_with_declarator+136>

125         }else {
126             printf("%s ", pop.string);
   0x08048a68 <+90>:    mov    0x804a038,%edx
   0x08048a6e <+96>:    lea    -0x1(%edx),%eax
   0x08048a71 <+99>:    mov    %eax,0x804a038
   0x08048a76 <+104>:   mov    %edx,%eax
   0x08048a78 <+106>:   shl    $0x6,%eax
   0x08048a7b <+109>:   add    %edx,%eax
   0x08048a7d <+111>:   add    $0x804a0c0,%eax
   0x08048a82 <+116>:   add    $0x1,%eax
   0x08048a85 <+119>:   sub    $0x8,%esp
   0x08048a88 <+122>:   push   %eax
   0x08048a89 <+123>:   push   $0x8048be4
   0x08048a8e <+128>:   call   0x8048410 <printf@plt>
   0x08048a93 <+133>:   add    $0x10,%esp

127         }
128     }
129 }
   0x08048a9f <+145>:   nop
   0x08048aa0 <+146>:   leave  
   0x08048aa1 <+147>:   ret    

End of assembler dump.

看到?jīng)]有,這個地方啥也沒發(fā)生。

但是,假如我們這個地方不是一個存在的函數(shù)名而是一個隨便的字符串,會怎么樣?

gcc -o cdecl ch3_cdecl.c -g
ch3_cdecl.c: In function ‘deal_with_declarator’:
ch3_cdecl.c:123:4: error: ‘dasgettoken’ undeclared (first use in this function)
    dasgettoken;
    ^
ch3_cdecl.c:123:4: note: each undeclared identifier is reported only once for each function it appears in

此時,編譯器會識別出這個名字,它是沒定義的identifier。

總結(jié)一下,如果想調(diào)用一個函數(shù),而忘記了它的參數(shù)列表,就只有一個函數(shù)名,編譯器是可以通過的。這是危險的。應(yīng)該對編譯器進(jìn)行配置以提醒這種情況。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容