各大编程语言经典的开始都是 hello world. 起源就不用说了(可以网上查到)。透过该简单的程序,我们应该从中知道些什么讯息,这是我们需要了解和掌握的。
先看一下 C 语言中, hello world 的代码吧:
#include <stdio.h> int main() { printf("Hello world!\n"); return 0; }
代码本身比较简单,主体只有一句:
printf("Hello world!\n");
这句话的作用就是在屏幕上打印出一句"hello world!".
我们来看一下 windows 和 Linux 中的运行结果吧:
windows 在控制台中输出了我们期待的结果,linux 也在终端中输出了字符串。到此,hello world 的主体功能结束。
接下来我们逐行分析一下hello world 的代码。
Line#1: #include <stdio.h>
这一句称为预处理,编译过程中称为预编译(pre-compile)。这句话的作用是将 stdio.h 中的代码块复制到代码文件的 #include 处。如果我们不加这一句,编译的时候会出现printf函数未定义的错误(警告)。编译器不同结果不同
gcc 会自动找到一些build-in 的函数,看起来这个程序能正常编译,但是会有隐患(如果自定义了同名函数,结果可能不是我们期待的,后续的博客中会说明)
我们看一下预编译后的结果:
...................... ...................... #line 723 "c:\\program files (x86)\\microsoft visual studio 11.0\\vc\\include\\stdio.h" #pragma pack(pop) #line 727 "c:\\program files (x86)\\microsoft visual studio 11.0\\vc\\include\\stdio.h" #line 2 "c:\\kylin\\consoleapplication1\\source.cpp" int main() { printf("Hello world!\n"); return 0; }
在main 函数之前,插入了一些代码块,这些都是由 stdio.h 文件带入
在gcc 中,插入类似的代码块
................ extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ; extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)); # 943 "/usr/include/stdio.h" 3 4 # 2 "hello.c" 2 int main() { printf("Hello world!\n"); }
第二行代码是函数入口 main 函数。C 和 C++ 应用程序入口都是 main 函数,代码中也应该只有一个main函数。可以在main函数中定义参数。
printf 是 stdio.h 中提供的C库函数,用来打印到屏幕上。
hello world 后跟的 "\n",是换行符,如果不加的话,打印结束后不会换行。
简单的 hello world 程序,实际包含了C/C++ 的几个编译相关问题:
- 预处理
- 编译
- 汇编
- 链接
下边几个代码如果不感兴趣,可以不用打开。
后续会有更精彩的博文。
因为gcc更灵活,使用gcc的代码块来示例。
当我们使用 gcc -S 参数时,生成汇编前的编译结果如下:
.file "hello.c" .section .rodata .LC0: .string "Hello world!" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $.LC0, %edi call puts popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)" .section .note.GNU-stack,"",@progbits
当使用 gcc -c 参数时,生成link前的代码如下:
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@<98>^B^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^@@^@^M^@^L^@UH<89>å¿^@^@^@^@è^@^@^@^@]ÃHello world!^@^@GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)^@^@^@^@^@^@^T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^H<90>^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@^P^@^@^@^@A^N^P<86>^BC^M^FK^L^G^H^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^D^@ñÿ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^D^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^G^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^H^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@