声明:新手入门,不完全靠谱历程,不具备教程水平,慎重参考阅读
一、用 gcc生成 .a 静态库和 .so 动态库
1、静态库
在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o 文件。
(1)、编辑生成例子程序hello.h 、hello.c 和 main.c。
tang@ubuntu:~$ mkdir test1 //建立目录//
tang@ubuntu:~$ cd test1 //进入目录//
//生成三个子程序//
tang@ubuntu:~/test1$ vi hello.h
tang@ubuntu:~/test1$ vi hello.c
tang@ubuntu:~/test1$ vi main.c
程序 1: hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO_H
程序 2: hello.c
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
程序3: main.c
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
(2)、将 hello.c 编译成.o 文件
输入命令生成hello.o
gcc -c hello.c
行 ls 命令看看是否生存了 hello.o 文件
(3)、由.o 文件创建静态库
键入以下命令将创建静态库文件libmyhello.a
ar -crv libmyhello.a hello.o
检查
(4)、在程序中使用静态库
# 方法一
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 是否真的连接到目标文件 hello 中
rm libmyhello.a
程序照常运行,静态库中的公用函数已经连接到目标文件中
2、动态库
(1)、由.o 文件创建动态库文件
在系统提示符下键入以下命令得到动态库文件 libmyhello.so
gcc -shared -fPIC -o libmyhello.so hello.o
(2)使用
# 方法一
gcc -o hello main.c -L. -lmyhello
# 方法二
gcc main.c libmyhello.so -o hello
会报错找不到该库文件
于是将文件 libmyhello.so 移动到目录/usr/lib再运行
sudo mv libmyhello.so /usr/lib
./hello
3、动态库和静态库生成可执行文件大小的对比
(1)创建目录进入目录创建子程序
(2)子程序
sub1.h
#ifndef SUB1_H
#define SUB1_H
float x2x(int a, int b);
#endif
sub1.c
#include"sub1.h"
float x2x(int a, int b){
return a * b; //相乘
}
sub2.h
#ifndef SUB2_H
#define SUB2_H
float x2y(int a, int b);
#endif
sub2.c
#include"sub2.h"
float x2y(int a, int b){
return a + b; //相加
}
main.c
#include<stdio.h>
#include"sub1.h"
#include"sub2.h"
int main(){
int a , b ;
printf("input a=");
scanf("%d",&a);
printf("\ninput b=");
scanf("%d",&b);
printf("\n%d * %d = %f\n", a, b, x2x(a, b));
printf("\n%d + %d = %f\n", a, b, x2y(a, b));
return 0;
}
(3)用静态库文件进行链接,生成可执行文件
I. 将 sub1.c、sub2.c 编译成 .o文件
gcc -c sub1.c sub2.c
II. .o文件创建静态库
ar -crv libsub1.a sub1.o
ar -crv libsub2.a sub2.o
III. 在程序中使用静态库
gcc main.c libsub1.a libsub2.a -o main1
./main1
IV. 查看大小
(4)用动态库文件进行链接,生成可执行文件
I. .o文件创建动态库
gcc -shared -fPIC -o libsub1.so sub1.o
gcc -shared -fPIC -o libsub2.so sub2.o
II. 在程序中使用动态库
gcc main.c libsub1.so libsub2.so -o main2
sudo mv libsub1.so /usr/lib
sudo mv libsub2.so /usr/lib
./main2
III. 查看大小
与静态库对比发现静态库更小
二、gcc不是一个人在战斗
1、gcc命令下各选项的含义
-E:仅作预处理,不进行编译、汇编和链接
-S:仅编译到汇编语言,不进行汇编和链接
-c:编译、汇编到目标代码(也就是计算机可识别的二进制)
-o:执行命令后文件的命名
-g:生成调试信息
-w:不生成任何警告
-Wall:生成所有的警告
2、gcc编译的四个步骤
预处理:gcc -E Test.c -o Test.i
编译: gcc -S Test.i -o Test.s
汇编: gcc -c Test.s -o Test.o
链接生成可执行文件: gcc Test.o -o Test
(实际操作前面用过就不另写了)
3、Binutils(一组二进制程序处理工具)
(1) addr2line:用来将程序地址转换成其所对应的程序源文件及所对应的代码
行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对
应的源代码位置。
(2) as:主要用于汇编,有关汇编的详细介绍请参见后文。
(3) ld:主要用于链接,有关链接的详细介绍请参见后文。
(4) ar:主要用于创建静态库。
(5) ldd:可以用于查看一个可执行程序依赖的共享库。
(6) objcopy:将一种对象文件翻译成另一种格式。
(7) objdump:主要的作用是反汇编。
(8) readelf:显示有关 ELF 文件的信息.
(9) size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等.
4、as汇编编译器
(1)下载安装nasm
输入以下命令安装nasm
sudo apt-get build-dep nasm
(2)用nasm编译
建立asm文件
touch hello.asm
gedit 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 ; 调用内核功能
生成hello.o
nasm -f elf64 hello.asm
生成一个可执行文件hello
ld -s -o hello hello.o
执行
nasm查看大小
size hello
c语言查看大小
size a.out
由此可以看出nasm方式编译得到的可执行文件比用gcc编译得到的文件小的多
三、Linux中的第三方库函数
1、光标库(curses)的主要函数功能
(1)清除屏幕
int erase(void);//在屏幕的每个位置写上空白字符
int clear(void);//使用一个终端命令来清除整个屏幕,相当于vi内的Ctrl+L
//内部调用了clearok来执行清屏操作,(在下次调用refresh时可以重现屏幕原文)
int clrtobot(void);//清除光标位置到屏幕结尾的内容
int clrtoeol(void);//清除光标位置到该行行尾的内容
(2)移动光标
int move(int new_y, int new_x); //移动stdcsr的光标位置
int leaveok(WINDOW *window_ptr,bool leave_flag);
//设置一个标志,用于控制在屏幕刷新后curses将物理光标放置的位置。
(3)窗口移动和更新屏幕
int mvwin(WINDOW *win, int new_y, int new_x); //移动窗口
int wrefresh(WINDOW *win);
int wclear(WINDOW *win);
int werase(WINDOW *win);
//类似于上面的refresh, clear, erase,但是此时针对特定窗口操作,而不是stdcur
int touchwin(WINDOW *win); //指定该窗口内容已改变、
//下次wrefresh时,需重绘窗口。利用该函数,安排要显示的窗口
int scrollok(WINDOW *win, bool flag); //指定是否允许窗口卷屏
int scroll(WINDOW *win); //把窗口内容上卷一行
2、安装curses库
输入以下命令安装curses
sudo apt-get install libncurses5-dev
3、体验一下即将绝迹的远古时代的BBS
打开控制面板点击程序
点击启用或关闭Windows功能
启用 “telnet client” 和"适用于Linux的Windows子系统"
开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,以游客身份体验一下即将绝迹的远古时代的 BBS
4、贪吃蛇游戏
代码参考Linux 环境下C语言编译实现贪吃蛇游戏
编译
gcc mysnake1.0.c -lcurses -o mysnake1.0
运行