龙空技术网

C语言学习第17篇---编译,链接过程探究

CodeAllen嵌入式 1470

前言:

现时看官们对“c语言链接过程细节”大约比较注意,你们都想要知道一些“c语言链接过程细节”的相关知识。那么小编在网上收集了一些关于“c语言链接过程细节””的相关资讯,希望朋友们能喜欢,姐妹们一起来学习一下吧!

原文首发于同名微信公号「Allen5G」,欢迎大家搜索关注,欢迎转发!

补充一个知识点:

&是一个位运算符,就是将两个二进制的数逐位相与,就是都是1才是1,只要有一个为0则为0,结果是相与之后的结果。

&&是一个逻辑运算符,就是判断两个表达式的真假性,只有两个表达式同时为真才为真,有一个为假则为假,具有短路性质。

编译器基本构成:

C语言编译基本流程图解:

就按照上边的流程一步步介绍下:

预编译:

处理所有的注释,以空格代替

将所有的#define删除,并且展开左右的宏定义

处理条件编译指令#if,#ifdef ,#elif ,#else , #endif

处理#include , 展开被包含的文件

保留编译器需要使用的#pragma指令

例子: gcc - E file.c -o file.i

编译:

~对预处理文件进行词法分析,语法分析和语义分析

语法分析:分析关键字,标识符,立即数等是否合法

语法分析:分析表达式是是否遵循语法规则

语义分析:在语法分析的基础上记忆布分析表达式是否合法

~分析结束后进行代码优化生成相应的汇编文件

编译指令实例: gcc -S file.i -o file.s

汇编:

汇编器将汇编代码转变为机器的可以执行的代码

每条汇编语句几乎都对应一条机器指令

汇编指令实例: gcc -c file.s -o file.o

实验1:源代码单步编译实例

#include "19-1.h"// Begin to define macro#define GREETING "Hello world!"#define INC(x) x++// Endint main(){  p = GREETING;  INC(i);  return 0;}# 1 "19-1.c"# 1 "<built-in>"# 1 "<command-line>"# 1 "/usr/include/stdc-predef.h" 1 3 4# 1 "<command-line>" 2# 1 "19-1.c"# 1 "19-1.h" 1# 9 "19-1.h"char* p = "Delphi";int i = 0;# 2 "19-1.c" 2# 11 "19-1.c"int main(){ p = "Hello world!"; i++; return 0;} .file "19-1.c" .globl p .section .rodata.LC0: .string "Delphi" .data .align 8 .type p, @object .size p, 8p: .quad .LC0 .globl i .bss .align 4 .type i, @object .size i, 4i: .zero 4 .section .rodata.LC1: .string "Hello world!" .text .globl main .type main, @functionmain:.LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq $.LC1, p(%rip) movl i(%rip), %eax addl $1, %eax movl %eax, i(%rip) movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE0: .size main, .-main .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits

.h

/* This is a header file. */char* p = "Delphi";int i = 0;

最后一个:链接

链接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接

图解:

静态链接:

由链接器在链接时将库的内容直接加到可执行程序中

linux下静态库的创建和使用

编译静态库源码; gcc -c lib.c -o lib.o生成静态库文件:ar -q lib.a lib.o使用静态库编译:gcc main.c lib.a -o main.out

实验1:静态链接实验 slib.c

#include <stdio.h>extern char* name();extern int add(int a, int b);int main(){ printf("Name: %s\n", name()); printf("Result: %d\n", add(2, 3)); return 0;}
char* name(){ return "Static Lib";}int add(int a, int b){ return a + b;}

动态链接:

可执行程序在运行时才会动态加载库进行链接

库的内容不会进入可执行程序当中

linux下动态库的创建和使用

编译动态库源码:gcc -shared dlib.c -o dlib.so

使用动态库编译:gcc main.c -ldl -o main.out

关键系统调用

dlopen:打开动态库文件

dlsym:查找动态库中的函数并返回调用地址

dlclose:关闭动态库文件

实验2:动态链接实验 dlib.c

#include <stdio.h>#include <dlfcn.h>int main(){ void* pdlib = dlopen("./dlib.so", RTLD_LAZY); char* (*pname)(); int (*padd)(int, int); if( pdlib != NULL ) { pname = dlsym(pdlib, "name"); padd = dlsym(pdlib, "add");  if( (pname != NULL) && (padd != NULL) ) { printf("Name: %s\n", pname()); printf("Result: %d\n", padd(2, 3)); } dlclose(pdlib); } else { printf("Cannot open lib ...\n"); } return 0;}
char* name(){ return "Dynamic Lib";}int add(int a, int b){ return a + b;}

标签: #c语言链接过程细节