新手小白尝试和编译器交朋友


声明:新手入门,不完全靠谱历程,不具备教程水平,慎重参考阅读

一、用 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 文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCy6vgg8-1602844801562)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602842941435.png)]

(3)、由.o 文件创建静态库

键入以下命令将创建静态库文件libmyhello.a

ar -crv libmyhello.a hello.o

检查

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ncVY8ME5-1602844801566)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843051375.png)]

(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

运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CDfsGcDa-1602844801569)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843175675.png)]

删除静态库文件试试公用函数 hello 是否真的连接到目标文件 hello 中

rm libmyhello.a

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjUTu3IM-1602844801570)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843226770.png)]

程序照常运行,静态库中的公用函数已经连接到目标文件中

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4IQwTwE-1602844801572)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843513866.png)]

3、动态库和静态库生成可执行文件大小的对比

(1)创建目录进入目录创建子程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oYRKqBnc-1602844801574)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843944615.png)]

(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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsLVWvLJ-1602844801576)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602843996613.png)]

II. .o文件创建静态库

ar -crv libsub1.a sub1.o
ar -crv libsub2.a sub2.o

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rnclOYiv-1602844801582)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844029507.png)]

III. 在程序中使用静态库

gcc main.c libsub1.a libsub2.a -o main1
./main1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jxnz99tI-1602844801585)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844085203.png)]

IV. 查看大小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0gF2Aq5e-1602844801586)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844542477.png)]

(4)用动态库文件进行链接,生成可执行文件

I. .o文件创建动态库

gcc -shared -fPIC -o libsub1.so sub1.o
gcc -shared -fPIC -o libsub2.so sub2.o

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5IwVoykM-1602844801587)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844179332.png)]

II. 在程序中使用动态库

gcc main.c libsub1.so libsub2.so -o main2
sudo mv libsub1.so /usr/lib
sudo mv libsub2.so /usr/lib
./main2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KzCFMUdY-1602844801589)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844322558.png)]

III. 查看大小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vggMGtXj-1602844801589)(C:\Users\15310\AppData\Roaming\Typora\typora-user-images\1602844605164.png)]

与静态库对比发现静态库更小

二、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

运行

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值