【问题标题】:C - what is the return value of a semicolon?C - 分号的返回值是多少?
【发布时间】:2010-01-15 11:31:20
【问题描述】:

我只是好奇下面的例子

#include<stdio.h>
int test();
int test(){
     //    int a = 5;
     //    int b = a+1;
     return ;
}
int main(){
     printf("%u\n",test());
     return 0;
}

我用 'gcc -Wall -o semicolon semicolon.c' 编译它以创建一个可执行文件 和 'gcc -Wall -S semicolon.c' 得到汇编代码:

    .file   "semicolon.c"
    .text
.globl test
    .type   test, @function
test:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    leave
    ret
    .size   test, .-test
    .section        .rodata
 .LC0:
    .string "%u\n"
    .text
 .globl main
    .type   main, @function
 main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %ecx
    subl    $20, %esp
    call    test
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    movl    $0, %eax
    addl    $20, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section        .note.GNU-stack,"",@progbits

因为我不是这样的汇编专家,我只知道 printf 打印 eax 中的内容 但我不完全理解 'movl %eax, 4(%esp)' 是什么意思,我假设在调用测试之前填充 eax 但那有什么价值呢? 4(%esp)是什么意思,esp的值是什么意思?

如果我取消注释 test() printf 中的行打印 6 - 这是用 eax 写的 ^^

【问题讨论】:

    标签: c


    【解决方案1】:

    你的汇编语言注释:

    test:
        pushl   %ebp        # Save the frame pointer
        movl    %esp, %ebp  # Get the new frame pointer.
        subl    $4, %esp    # Allocate some local space on the stack.
        leave               # Restore the old frame pointer/stack
        ret
    

    请注意,测试中没有任何内容涉及 eax。

    .size   test, .-test
    .section        .rodata
     .LC0:
    .string "%u\n"
    .text
     .globl main
    .type   main, @function
    main:
    leal    4(%esp), %ecx      # Point past the return address.
    andl    $-16, %esp         # Align the stack.
    pushl   -4(%ecx)           # Push the return address.
    pushl   %ebp               # Save the frame pointer
    movl    %esp, %ebp         # Get the new frame pointer.
    pushl   %ecx               # save the old top of stack.
    subl    $20, %esp          # Allocate some local space (for printf parameters and ?).
    call    test               # Call test.
    

    请注意,此时,没有任何内容修改 eax。进入 main 的内容仍然存在。

    movl    %eax, 4(%esp)      # Save eax as a printf argument.
    movl    $.LC0, (%esp)      # Send the format string.
    call    printf             # Duh.
    movl    $0, %eax           # Return zero from main.
    addl    $20, %esp          # Deallocate local space.
    popl    %ecx               # Restore the old top of stack.
    popl    %ebp               # And the old frame pointer.
    leal    -4(%ecx), %esp     # Fix the stack pointer,
    ret
    

    所以,打印出来的就是 main 中的任何内容。正如其他人指出的那样,它是未定义的:这取决于启动代码(或操作系统)之前对 eax 所做的操作。

    【讨论】:

    • 很好的解释。要添加有关此主题的更多信息,似乎 eax 及其通过堆栈传递值的用法对于简单数据类型(int、double、char、void*、...)是相似的,但随着它进入更多的结构编译器的内存管理开始发挥作用。我还不确定在结构的情况下堆栈会发生什么,以了解应该返回结构的非 void 函数的空返回,但这是一个更复杂的问题/答案。无论如何-谢谢
    • @John:结构与ints 和floats 发生的情况几乎相同。它被称为堆栈垃圾。调用者为返回值保留的内存中发生的任何事情都是返回
    【解决方案2】:

    分号没有返回值,你所拥有的是一个“空返回”,就像用于从 void 函数返回的那个 - 所以该函数不返回任何东西。

    这实际上在编译时会导致警告:

    warning: `return' with no value, in function returning non-void
    

    在调用test 之前,我没有看到eax 中有任何内容。

    大约 4(%esp),这意味着从堆栈指针 (esp) + 4 中取值。即堆栈上的最后一个单词。

    【讨论】:

    • 似乎我混合了英特尔和 AT&T 汇编语法,所以你的权利,eax 没有写。所以 'movl %eax, 4(%esp)' 意味着 eax 被推入堆栈,对吧?
    • 不是,表示eax的值存放在[esp+4]中,可能是栈上的某个局部变量
    【解决方案3】:

    int 函数的返回值在 EAX 寄存器中传递。测试函数没有设置 EAX 寄存器,因为没有给出返回值。因此结果是不确定的。

    【讨论】:

    • 所以结果不是未定义,而是在eax中找到的值,对吧?根据定义,它被称为“未定义”
    • 是的,结果是 EAX 中的值。由于 EAX 没有明确设置,它的值是由一些未知的先前操作确定的。这就是我们所说的“未定义”。
    【解决方案4】:

    分号确实没有价值。

    我认为正确的答案是int 函数的return &lt;nothing&gt; 是一个错误,或者至少具有未定义的行为。这就是为什么用-Wall 编译它会产生

    semi.c: In function ‘test’:
    semi.c:6: warning: ‘return’ with no value, in function returning non-void
    

    至于%4,esp 持有什么......它是堆栈上没有(有意)存储任何内容的位置,因此它可能会返回在该位置找到的任何垃圾。这可能是对函数中的变量进行评估的最后一个表达式(如您的示例)或完全不同的东西。这就是“未定义”的全部意义所在。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-06
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多