C函数调用而忘记参数列表的后果 [C专家编程]

故事从C专家编程的第三章分析C语言的声明开始,书中给出了cdecl代码,正好昨天把整章看完,所以今天就想着把程序抄一边,然后搞懂一下怎么回事。代码可以参考此链接

这儿只将涉及到我的问题的部分代码摘录下来,原始代码:

void deal_with_declarator()  
{  
    /*处理标识符之后可能存在的数组/函数*/  
    switch(this.type)  
    {  
        case '[':  
            deal_with_arrays();  
                 break;  
        case '(':  
                 deal_with_function_args();  
                 break;  
    }  
    deal_with_pointers();  
    /*处理在读入到标识符之前压入到堆栈的符号*/  
    while(top>=0)  
    {  
        if(stack[top].type=='('){  
            pop;  
            gettoken();/*读取')'之后的符号*/  
            deal_with_declarator();  
        }  
        else  
        {  
            printf("%s ",pop.string);  
        }  
    }  
}  
int main()  
{  
    /*将标记压入堆栈中,直到遇见标识符*/  
    read_to_first_identifier();  
    deal_with_declarator();  
    printf("\n");  
    return 0;  
}  

而我在抄的时候将deal_with_declarator函数内部的一个函数调用忘记了()

        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>  #函数调用

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行是调用函数gettoken

我们再看看错误代码的汇编结果:

(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;   #看到没,啥也没做
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.

看到没有,这个地方啥也没发生。

但是,假如我们这个地方不是一个存在的函数名而是一个随便的字符串,会怎么样?

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

总结一下,如果想调用一个函数,而忘记了它的参数列表,就只有一个函数名,编译器是可以通过的。这是危险的。应该对编译器进行配置以提醒这种情况。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容