现代系统:
% pacman -Q glibc gcc
glibc 2.16.0-4
gcc 4.7.1-6
% uname -sr
Linux 3.5.4-1-ARCH
一个简单的程序:
% < wtf.c
void main(){}
让我们做静态和动态构建:
% gcc -o wtfs wtf.c -static
% gcc -o wtfd wtf.c
一切都很好看:
% file wtf?
wtfd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x4b421af13d6b3ccb6213b8580e4a7b072b6c7c3e, not stripped
wtfs: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0x1f2a9beebc0025026b89a06525eec5623315c267, not stripped
有人可以向我解释一下吗?
% for n in $(seq 1 10); do ./wtfd; echo $?; done | xargs
0 0 0 0 0 0 0 0 0 0
% for n in $(seq 1 10); do ./wtfs; echo $?; done | xargs
128 240 48 128 128 32 64 224 160 48
当然,可以使用int main()
。 -Wmain
会发出警告(return type of ‘main’ is not ‘int’
)。
我只想了解那里发生了什么。
答案 0 :(得分:6)
这完全是重点。
没有“void main()”。总有一个结果值,如果你没有返回一个并且在你的程序中没有做任何事情,那么返回值就是在程序启动时恰好在适当的寄存器中发生的事情(或者具体地说,无论什么时候发生在那里) main从启动代码调用)。这当然可以取决于程序在main之前正在做什么,例如处理共享库。
编辑:想知道如何发生这种情况,试试这个:
int foo(void)
{
return 55;
}
void main(void)
{
foo();
}
当然没有保证,但是这个程序很可能会有55的退出代码,因为这是某个函数返回的最后一个值。试想一下,调用发生在main之前。
答案 1 :(得分:2)
进一步说明基督徒所说的话。即使您声明void main()
,您的进程也将返回eax
中之前的任何值(因为您使用的是linux x86 arch)。
void main() {
asm("movl $55, %eax");
}
所以现在它总是返回55 b / c,上面的代码显式初始化eax
。
$ cc rval.c
$ ./a.out
$ echo $?
55
此示例仅适用于当前主要操作系统,因为我假设调用约定。没有理由操作系统不能有不同的调用约定,返回值可能在其他地方(RAM,寄存器,等等)。