赞
踩
写下第一个hello word!! C语言程序,在集成开发环境中,只需点击编译按钮就能一键生成可执行程序,整个过程看似波澜不惊,但是其编译器却像过山车一样。从代码到可执行文件大致可分为4部分:预编译,编译,汇编,链接。
话不多,上干货
预编译:预编译的作用是把程序中的宏定义、头文件全部展开、处理条件编译的真假值、去掉注释等作用,最后预编译得到的是一个纯净的C文件。
在gcc中利用gcc -E xxx.c -o xxx.i得到预编译后的文件。
下面来对test.c文件进行预编译:
代码如下(示例):
#include <stdio.h> #include <stdlib.h> #define MAXOPTIONS 100 #define MAXVal 20 /*fun*/ int fun(void) { printf("fun !"); } /*mian.c*/ int main(int argc, char **argv) { int value; printf("main"); return 0; }
得到预编译文件test.i如下(示例):
# 1 "test.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "test.c" # 1 "/usr/include/stdio.h" 1 3 4 # 27 "/usr/include/stdio.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4 # 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4 # 1 "/usr/include/features.h" 1 3 4 # 424 "/usr/include/features.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4 # 427 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4 # 428 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4 # 429 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4 # 425 "/usr/include/features.h" 2 3 4 # 448 "/usr/include/features.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4 # 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4 # 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4 # 449 "/usr/include/features.h" 2 3 4 # 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4 # 28 "/usr/include/stdio.h" 2 3 4 # 1 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 1 3 4 # 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4 # 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4 typedef long unsigned int size_t; # 34 "/usr/include/stdio.h" 2 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4 # 27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4 # 28 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4 . . . . # 9 "test.c" int fun(void) { printf("fun !"); } int main(int argc, char **argv) { int value; printf("main"); return 0; }
编译:分析语法语义,优化后生成相应的汇编代码文件,最复杂最核心的步骤
gcc -S test.c -o test.s 得到汇编.s文件
代码如下(示例):
.file "test.c" .text .section .rodata .LC0: .string "fun !" .text .globl fun .type fun, @function fun: .LFB5: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE5: .size fun, .-fun .section .rodata .LC1: .string "main" .text .globl main .type main, @function main: .LFB6: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movl %edi, -4(%rbp) movq %rsi, -16(%rbp) leaq .LC1(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE6: .size main, .-main .ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0" .section .note.GNU-stack,"",@progbits
汇编器是将汇编代码转变成机器可以执行的指令,几乎每一条汇编语句都对应一条机器指令。因此汇编过程非常简单。根据汇编指令和机器指令的对照表进行翻译就行了。
gcc -c test.s -o test.o得到二进制.o文件
项目不止一个文件组成,有多个C语言模块,每个模块之间存在函数和变量的访问,那就需要知道模块和函数的地址,因此模块间这种调用关系需要用规定好的符号联系起来,所以这个模块间的拼接过程就是链接过程
在gcc中用gcc test.o -o text.out生成
或者直接gcc test.c -o text.out
以上就是整个c代码到可执行程序的整个过程!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。