目录
1.可执行文件的组装学习使用gcc生成静态库和动态库静态库生成动态库生成使用实例静态库使用动态库使用2.gcc编译的各种工具关于gcc编译器下的工具Binutilsc运行库gcc的编译过程用nasm汇编编译器编译生成执行程序3.库函数的运用从光标库(curses)的主要函数功能了解库函数的作用在Ubuntu中安装curses库Linux 环境下C语言编译实现贪吃蛇游戏4.参考资料1.可执行文件的组装
学习使用gcc生成静态库和动态库
在平时工作中,我们通常把公有函数制作成函数库,供其他程序使用,函数库又分为静态库和动态库。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
静态库生成
这里使用最简单的Hello World程序来演示。
创建hello.c和main.c文件
使用touch命令创建
touch hello.ctouch main.c
使用vi对程序进行编译
vi hello.cvi main.c
hello.c
#include <stdio.h>void hello(){printf("Hello World\n");}
main.c
#include <stdio.h>main(){hello();return 0;}
将hello.c编译成.o文件
输入以下命令,即可形成
gcc -c hello.c
由.o文件生成静态库
使用 ar 命令,即可生成.a文件
ar -crv libhello.a hello.o
注:静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。
在程序中使用静态库
使用命令
gcc main.c libhello.a -o hello
从静态库中将公用函数连接到目标文件中
生成目标文件hello
运行hello程序
动态库生成
由.o文件生成动态库使用命令,生成.so文件
gcc -shared -fPIC -o libhello.so hello.o
在程序中使用动态库
使用命令
gcc main.c libhello.so -o hello
运行程序
使用实例
静态库使用
编辑x2x和x2y函数,实现计算两个数的加减运算x2x
int x2x(int a, int b) {return a+b;}
x2y
int x2y(int a, int b) {return a-b;}
main
#include<stdio.h>int main() {int a=2;int b=3;printf("a+b=%d\n",x2x(a,b));printf("a-b=%d\n",x2y(a,b));}
使用gcc命令生成3个.o文件
将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件
ar -crv libsub.a sub1.o sub2.o
用 gcc将 main函数的目标文件与静态库文件进行链接,生成最终的可执行程序
gcc main.c libsub.a -o main
运行程序
其文件大小为
动态库使用
由.o文件生成动态库使用命令,生成.so文件
gcc -shared -fPIC -o libsub.so sub1.o sub2.o
用 gcc将 main函数的目标文件与动态库文件进行链接
gcc main.c libsub.so -o main2
运行程序
出现错误,找不到动态库文件
解决方法:将.so文件复制到lib文件夹里面
sudo cp libsub.so /usr/lib
重新运行
成功
文件大小为:
结论:使用静态库生成的目标程序比使用动态库生成的目标程序大
2.gcc编译的各种工具
关于gcc编译器下的工具
Binutils
Binutils是一组二进制程序处理工具,包括以下几种
(1) addr2line:用来将程序 地址转 换成其所 对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置。
(2) as:主要用于汇编。
(3) ld:主要用于链接。
(4) ar:主要用于创建静态库。
(5) ldd:可以用于查看一个可执行程序依赖的共享库。
(6) objcopy:将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或
者将.elf 转换成.bin 等。
(7) objdump:主要的作用是反汇编。
(8) readelf:显示有关 ELF 文件的信息。
(9) size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小
等。
c运行库
C 语言标准主要由两部分组成:一部分描述 C 的语法,另一部分描述 C 标准库。C 标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类型声明和宏定义,譬如常见的 printf 函数便是一个 C 标准库函数,其原型定义在 stdio 头文件中。
C 语言标准仅仅定义了 C 标准库函数原型,并没有提供实现。因此,C 语言编译
器通常需要一个 C 运行时库(C Run Time Libray,CRT)的支持。C 运行时库又常简称为 C 运行库。与 C 语言类似,C++也定义了自己的标准,同时提供相关支持库,称为 C++运行时库。
gcc的编译过程
gcc的编译过程分为4步:预编译,编译,汇编,链接
这里使用一个简单的程序来演示这个过程
当使用gcc直接编译以下代码时
//hello.c#include <stdio.h>int main(){printf("Hello World!\n");return 0;}
只需要使用
gcc hello.c -o hello
就能生成可执行文件
把编译过程分为四步
预编译
gcc -E hello.c -o hello.i
以输出 的hello.i 文件中存放着 hello.c 经预处理之后的代码
编译
gcc -S hello.i -o hello.s
预处理之后,直接对生成的 hello.i 文件编译,生成汇编代码
汇编
gcc -c hello.s -o hello.o
对生成的汇编代码文件 hello.s,gas 汇编器负责将其编译为目标文件
链接
gcc hello.o -o hello
将生成的 hello.o 与C标准输入输出库进行连接,最终生成程序 hello
运行程序
用nasm汇编编译器编译生成执行程序
nasm安装过程不在此赘述
创建hello.asm文件
touch hello.asm
编译hello.asm文件
将下列代码拷贝进hello.asm文件中
; hello.asm section .data ; 数据段声明msg db "Hello, world!", 0xA; 要输出的字符串len equ $ - msg ; 字串长度section .text ; 代码段声明global _start ; 指定入口函数_start: ; 在屏幕上显示一个字符串mov edx, len; 参数三:字符串长度mov ecx, msg; 参数二:要显示的字符串mov ebx, 1 ; 参数一:文件描述符(stdout) mov eax, 4 ; 系统调用号(sys_write) int 0x80 ; 调用内核功能; 退出程序mov ebx, 0 ; 参数一:退出代码mov eax, 1 ; 系统调用号(sys_exit) int 0x80 ; 调用内核功能
编译文件
nasm -f elf64 hello.asm
链接文件
ld -s -o hello hello.o
运行程序
./hello
成功
可以看到由nasm生成的程序大小比C代码的编译生成的程序小的多
3.库函数的运用
从光标库(curses)的主要函数功能了解库函数的作用
curses是一个在Linux/Unix下广泛应用的图形函数库,作用是可以在终端内绘制简单的图形用户界面。
其基本函数名称和功能
1、move(y,x);将光标移动至(x,y)处。
2、refresh();我们写入的内容首先会在系统缓冲区中,经过refresh()函数刷新之后才能够显示到屏幕上。
3、echo()和noecho();输入的字符显示和不显示在终端上。可以用密码输入。
4、输出:
addch();显示一个字符
addstr();显示一串字符串
printw(“格式”,变量);显示指定格式的内容,类似于printf();
mvaddstr();移动到某个位置输出。
5、输入:
getch();输入一个字符
getstr();输入一串字符串
scanw("%s",s);;按指定格式输入内容,类似于scanf();
mvaddstr();移动到某个位置输入。
在Ubuntu中安装curses库
输入命令,安装
sudo apt-get install libncurses5-dev
Linux 环境下C语言编译实现贪吃蛇游戏
创建文件后将代码放进文件中
使用以下命令进行编译
c mysnake1.0.c -lcurses -o mysnake1.0
成功运行
4.参考资料
Linux 环境下C语言编译实现贪吃蛇游戏:
/Linux/-08/41375.htm