GCC编译器背后的故事

1、用GCC生成.a静态库和.so动态库

一、建立一个 test2 文件夹,并在该文件夹中建立三个子程序 hello.h、hello.c 和 main.c(这里还须要下vim)
在这里插入图片描述
解决后,在vim中输入咱们建立的三个字程序代码web

#ifndef HELLO_H 
#define HELLO_H 
void hello(const char *name); 
#endif //HELLO_H
#include <stdio.h> 
#include "hello.h"
void hello(const char *name) 
{
 printf("Hello %s!\n", name);
}
#include "hello.h" 
int main() 
{
 hello("everyone"); 
 return 0; 
}

以下(程序main.c为例)
在这里插入图片描述
在这里插入图片描述二、后将hello.h编译成.o文件,可是这里须要安装gcc编程

在这里插入图片描述
(安装过程同上面vim差很少,有点多这里就不放出来了)
在这里插入图片描述
三、由 .o文件建立静态库,并在程序中使用
a…o文件建立静态库
在这里插入图片描述
b. 在程序中使用静态库
方法一
gcc -o hello main.c -L. -lmyhello
方法二
gcc main.c libmyhello.a -o hello
方法二
gcc -o main.c # 先生成 main.o
gcc -o hello main.o libmyhello.a
而后./hello,执行程序
在这里插入图片描述
咱们可尝试删除 libmyhello静态库,再次执行 hello 程序(看程序运行时,是否须要该静态库)ubuntu

在这里插入图片描述
结果:静态库在程序编译时会被链接到目标代码中,程序运行时将再也不须要该静态库。
四、由 .o文件建立动态库,并在程序中使用
a. .o文件建立动态库
在这里插入图片描述
b. 在程序中使用动态库vim

方法一

gcc -o hello main.c -L. -lmyhellosvg

方法二

gcc main.c libmyhello.so -o hello函数

在这里插入图片描述
(缘由:程序在运行时, 会在/usr/lib 和/lib 等目录中查找须要的动态库文件。若找到,则载入动态库,不然将提示相似上述错误而终止程序运行)
解决方法:将文件 libmyhello.so 移动到目录/usr/lib 中
在这里插入图片描述ui

2、静态库与动态库生成执行文件大小比较

一、建立一个 test3文件夹,并在该文件夹中分别建立子程序 sub1.h、sub1.c、sub2.h、sub2.c、main.c
mkdir test3
cd test3
vim sub1.h
vim sub1.c
vim sub2.h
vim sub2.c
vim main.c
而后在vim输入他们的程序代码,同上.net

#ifndef SUB1_H
#define SUB1_H 
float x2x(int a, int b);
#endif //SUB1_H
#include"sub1.h"
float x2x(int a,int b)
{
return a+b;
}
#ifndef SUB2_H
#define SUB2_H 
float x2y(int a, int b);
#endif //SUB2_H
#include"sub2.h"
float x2y(int a,int b)
{
return a*b;
}
#include<stdio.h>
#include"sub1.h"
#include"sub2.h"
int main(){
int a=2,b=3;
	printf("%d + %d = %f\n", a, b, x2x(a, b));
	printf("%d × %d = %f\n", a, b, x2y(a, b));
	return 0;

}

以第一个为例,输入过程以下
在这里插入图片描述
在这里插入图片描述
二、用静态库文件进行连接,生成可执行文件
a. 将 sub1.c、sub2.c 编译成 .o文件
在这里插入图片描述
b. .o文件建立静态库
在这里插入图片描述命令行

c. 在程序中使用静态库
在这里插入图片描述
三、用动态库文件进行连接,生成可执行文件
a. .o文件建立动态库
在这里插入图片描述
b. 在程序中使用动态库
在这里插入图片描述
(在这以前,显示了一次错误,说找不到目录,而后再试了一遍,就能够了)
d. 两个可执行文件大小的比较debug

gcc -static main.c libsub1.a libsub2.a -o main1 # 从新由静态库生成
size main1
ldd main1
size main2
ldd main2

在这里插入图片描述

3、gcc编译器是怎么编译的

一、建立一个 test0 文件夹,并在该文件夹中建立一个 hello.c 程序
代码以下

#include<stdio.h>
int main (void)
{
 printf("Hello World!\n");
 return 0;
}

二、程序的编译过程在这里插入图片描述
a. 预编译(将源文件 hello.c 文件预处理生成 hello.i)
b. 编译(将预处理生成的 hello.i 文件编译生成汇编程序 hello.s)
c. 汇编(将编译生成的 hello.s 文件汇编生成目标文件 hello.o)
d. 连接(分为静态连接和动态连接,生成可执行文件)
以下图
在这里插入图片描述
e. 用 size 查看文件大小,ldd连接了那些动态库
在这里插入图片描述
三、ELF 文件的分析
(1) .text:已编译程序的指令代码段
(2) .rodata:ro 表明 read only,即只读数据(譬如常数 const)
(3) .data:已初始化的 C 程序全局变量和静态局部变量
(4) .bss:未初始化的 C 程序全局变量和静态局部变量
(5) .debug:调试符号表,调试器用此段的信息帮助调试
在这里插入图片描述
b. 反汇编 ELF
objdump -S 将其反汇编而且将其 C 语言源代码混合显示出来:
在这里插入图片描述
四、在ubuntu中下载安装nasm,对示例汇编代码“hello.asm”编译生成可执行程序,并与上述用C代码的编译生成的可执行程序大小进行对比
a. 安装nasm编译器
下载 NSAM 软件包:连接: link.
输入sudo apt install nasm

在这里插入图片描述
输入nasm -version

在这里插入图片描述
b. 编译汇编 hello.asm文件,并于C代码的编译生成的程序大小进行对比
hello.asm 内容以下:
在这里插入图片描述

编译
nasm -f elf64 hello.asm
连接
ld -s -o hello hello.o

在这里插入图片描述
c. 汇编与C代码的编译生成的可执行程序大小对比
在这里插入图片描述

4、了解实际程序是如何借助第三方库函数完成代码设计

(一)、以游客身份体验一下即将绝迹的远古时代的BBS
在win10下,打开控制面板——>程序——>启用或关闭Windows功能,启动"telnet client" 和"适用于Linux的Windows子系统"如图
在这里插入图片描述
b. 打开一个 cmd命令行窗口,输入以下命令: telnet bbs.newsmth.net
在这里插入图片描述
二、Linux 环境下C语言编译实现贪吃蛇游戏
a. 了解Linux 系统中终端程序最经常使用的光标库(curses)
initscr(): initscr() 是通常 curses 程式必须先呼叫的函数, 一但这个函数被呼叫以后, 系统将根据终端机的形态并启动 curses 模式
endwin(): curses 一般以呼叫 endwin() 来结束程式. endwin() 可用来关闭curses 模式, 或是暂时的跳离 curses 模式
refresh(): refresh() 为 curses 最常呼叫的一个函式
move(y,x): 将游标移动至 x,y 的位置
echochar(ch)/addch(ch): 显示某个字元
b. Ubuntu18.04 安装curses库
可经过 whereis 命令头文件和库文件都被安装到哪些目录中:
c. Linux 环境下C语言编译实现贪吃蛇游戏

mkdir testSnake
cd testSnake
vim mysnake.c
gcc mysnake.c -lcurse -o mysnake
./mtsnake

./mysnake 运行该程序,效果以下:
在这里插入图片描述

5、参考连接

连接: link.