2010-01-15 34 views
3

IM只是好奇下面的例子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.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的意思是什么?

如果我取消测试()行的printf打印6 - 这是写在EAX ^^

回答

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所做的工作。

+0

很好的解释。添加一些关于这个主题的更多信息,似乎eax及其在通过堆栈传递值时的用法与简单数据类型(int,double,char,void *,...)类似,但是当它进入更多的结构时编译器的内存管理发挥作用。即时通讯还不确定在堆栈上发生什么情况,以便理解空函数返回结构的空函数,但这是一个更复杂的问题/答案。无论如何 - thx – 2010-01-15 12:17:42

+0

@John:几乎同样的事情发生在像'int'和'float'一样的结构中。它被称为_stack垃圾_。无论内存中调用者为返回值保留的是什么,返回_returned_。 – 2010-01-15 12:52:58

7

分号没有返回值,你有什么是“空回”,喜欢使用的一个从void函数返回 - 所以函数不返回任何东西。

编译时,这实际上将导致警告:

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

而且我没有看到任何东西放在eax调用test之前。

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

+0

似乎我混合英特尔和AT&T汇编语法,所以你的权利,EAX没有写。所以'movl%eax,4(%esp)'意味着eax被推入堆栈,对吧? – 2010-01-15 12:01:27

+0

不,这意味着eax的值存储在[esp + 4]中,这可能是堆栈 – 2010-01-15 12:14:09

2

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

+0

上的一些局部变量,所以结果不是未定义的,但在eax中找到的值是正确的?这在定义上被称为'undefined' – 2010-01-15 12:06:29

+0

是的,结果是EAX中的值。由于EAX没有明确设置,它的值由某个未知的以前的操作决定。这就是我们所说的'未定义'。 – Tomas 2010-01-18 11:12:14

0

分号确实没有任何价值。

我认为正确的答案是函数是一个错误,或至少有未定义的行为。这就是为什么有-Wall编译这会产生

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

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

相关问题