编译与链接过程详解

1.常见预定义符号的含义
FILE //进⾏编译的源⽂件
LINE //⽂件当前的⾏号
DATE //⽂件被编译的⽇期
TIME //⽂件被编译的时间
STDC //如果编译器遵循ANSI C,其值为1,否则未定义

注:这些预定义符号的首尾为两个下划线,如果是两个单词,中间以一个下划线连接;如果在源代码使用这些预定义符号,它们会在预处理阶段被转换。
在Windows系统下测试结果:
这里写图片描述

2.预处理符号#与##
一般用法 ,我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
C语言中的#号和##号的作用详情见:
http://blog.chinaunix.net/uid-27666459-id-3772549.html

3.宏和函数的区别
a.宏会在编译器在对源代码进行编译的时候进行简单替换,不会进行任何逻辑检测,即简单代码复制而已。
b.宏进行定义时不会考虑参数的类型。
c.参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。
d.参数宏的运行速度会比函数快,因为不需要参数压栈/出栈操作。
e.参数宏在定义时要多加小心,多加括号。
f.函数只在目标文件中存在一处,比较节省程序空间。
g.函数的调用会牵扯到参数的传递,压栈/出栈操作,速度相对较慢。
h.函数的参数存在传值和传地址(指针)的问题,参数宏不存在。

4.编译链接的整个过程和详细的每个过程
因为Windows的VS为集成开发环境,集编译、汇编、链接于一体,而Linux通过单独工具进行编译、汇编、链接,所以要想详细的了解编译链接过程需要在Linux系统下进行。电脑只能识别二进制序列,而我们的代码是利用C语言写的,需要转换位机器所能识别的二进制序列,编译链接过程就是将代码转换成机器所能识别的二进制序列(目标文件)并生成可执行文件的过程。
整个过程为:
这里写图片描述
1.预处理:其中预处理阶段主要完成4个任务
a.宏替换
b.头文件展开
c.去注释
d.条件编译
linux下使用的gcc选项:
gcc -E test.c -o test.i
其中test.c为存放的源文件代码,生成目标文件test.i。
test.i的源文件代码:

#include <stdio.h>
#define M 4
int main()
{
   printf("helllo word\n");  //printf hello word.
   printf("%d\n",M);
   #if M
   printf("hello word\n");
   #endif
   return 0;
}

由于经预处理之后代码文件太长,所以只截取部分代码:

# 938 "/usr/include/stdio.h" 3 4

# 2 "test.c" 2

int main()
{
   printf("helllo word\n");
   printf("%d\n",4);

   printf("hello word\n");

   return 0;
}

明显可以看出完成了预处理的a、b、c、d四个任务.
2.编译:经过预处理阶段生成test.i文件之后,在经过编译过程,生成test.s文件,即汇编语言代码。
Linux下的gcc命令选项为-S:
gcc test.c -S -o test.s
生成的目标文件tset.s文件即汇编语言代码如下:

.file   "test.c"
    .section    .rodata
.LC0:
    .string "helllo word"
.LC1:
    .string "%d\n"
.LC2:
    .string "hello word"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, (%esp)
    call    puts
    movl    $.LC1, %eax
    movl    $4, 4(%esp)
    movl    %eax, (%esp)
    call    printf
    movl    $.LC2, (%esp)
    call    puts
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)"
    .section    .note.GNU-stack,"",@progbits

3.汇编:经过编译阶段生成test.s文件之后,在经过汇编过程,生成test.o文件,即计算机能够识别的二进制乱码。
Linux下的gcc命令选项为-o:
gcc test.c -c -o test.o
生成的目标文件tset.o文件即二进制代码(部分)如下(使用od命令将二进制乱码有序排列):

0000100 000000 000000 176350 177777 134377 000014 000000 042307
0000120 002044 000004 000000 002211 164044 177774 177777 002307
0000140 010044 000000 164000 177774 177777 000270 000000 144400
0000160 000303 000000 062550 066154 067554 073440 071157 000144
0000200 062045 000012 062550 066154 020157 067567 062162 000000
0000220 041507 035103 024040 047107 024525 032040 032056 033456
0000240 031040 030460 030062 030463 020063 051050 062145 044040
0000260 072141 032040 032056 033456 032055 000051 027000 074563
0000300 072155 061141 027000 072163 072162 061141 027000 064163
0000320 072163 072162 061141 027000 062562 027154 062564 072170
0000340 027000 060544 060564 027000 071542 000163 071056 062157
0000360 072141 000141 061456 066557 062555 072156 027000 067556
0000400 062564 043456 052516 071455 060564 065543 000000 000000
0000420 000000 000000 000000 000000 000000 000000 000000 000000
*

4.链接:经过汇编阶段生成test.o文件之后,在经过链接之后,生成.out可执行文件。
Linux下的gcc命令为:
gcc test.c
生成a.out的可执行文件,打开之后:

helllo word
4
hello word

上述就是整个编译链接过程。
4.关于预处理阶段的条件编译详细说明。
条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。
详细说明:
http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值