我刚看到这个here
#include <stdio.h>
int main(int argc, char *argv[printf("Hello, world!\n")]) {}
这是打印“Hello World!”
但是这里到底发生了什么?
我能猜到的最好的是它被编译并抛出执行堆栈的顶部,但语法对我来说看起来不合法......
答案 0 :(得分:21)
该代码使用C99的可变长度数组功能,该功能允许您声明仅在运行时知道其大小的数组。 printf
返回一个等于实际打印的字符数的整数,因此代码打印出“Hello,world!”首先,使用返回值作为argv
的大小。 main
函数本身什么都不做。 对 printf
本身的实际调用可能会进入编译器生成的启动代码,而编译器又会调用main
。
修改:我刚刚检查了gcc
生成的代码的反汇编,看来printf
的调用是在main
内进行的其他代码。
答案 1 :(得分:5)
如果我弄清楚编译器如何解析它,我会更新它,但至少不需要猜测它是如何编译的:
objdump --disassemble /tmp/hello (edited):
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 10 sub $0x10,%esp
80483cd: b8 a0 84 04 08 mov $0x80484a0,%eax
80483d2: 89 04 24 mov %eax,(%esp)
80483d5: e8 22 ff ff ff call 80482fc <printf@plt>
80483da: c9 leave
80483db: c3 ret
80483dc: 90 nop
80483dd: 90 nop
80483de: 90 nop
80483df: 90 nop
由于Linux可执行文件通常位于0x8048000,因此printf参数的地址与二进制文件的起始位置的偏移量为0x00004a0:
xxd /tmp/hello | grep 00004a0
00004a0: 4865 6c6c 6f2c 2077 6f72 6c64 210a 0000 Hello, world!...
因此,推送字符串的地址,并使用该arg调用printf。没有什么神奇的,所以有趣的东西都是由gcc完成的。
答案 2 :(得分:4)
答案 3 :(得分:-1)
我不是C专家,但看起来命令行参数与main
同时声明。