C - 分号的返回值是多少?

时间:2010-01-15 11:31:20

标签: c

我对以下示例感到好奇

#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)'意味着我在调用test之前假设填充eax 但那么价​​值是多少?什么意思是4(%esp)和esp的意思是什么意思?

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

4 个答案:

答案 0 :(得分:9)

您的汇编语言注释:

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。无论是什么进入主要仍然在这里。

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

所以,打印出来的是主要内容。正如其他人指出的那样,它是未定义的:它取决于启动代码(或操作系统)之前为eax做了什么。

答案 1 :(得分:7)

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

这实际上在编译时会发出警告:

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

在致电eax之前,test没有看到任何内容。

大约4(%esp),这意味着从堆栈指针(esp)+ 4中获取值。堆栈前面的一个字。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

分号确实没有价值。

我认为正确的答案是return <nothing>函数的int是错误的,或者至少有未定义的行为。这就是用-Wall产生

来编译它的原因
semi.c: In function ‘test’:
semi.c:6: warning: ‘return’ with no value, in function returning non-void

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