ubuntu下用gcc生成与使用静态库和动态库以及与其他编译器的对比和函数库的应用

本文详述了在Ubuntu环境下,使用GCC生成和使用静态库与动态库的过程,并对比了两者在生成可执行文件上的差异。同时,通过实例展示了静态库和动态库的链接方法。此外,还对比了GCC和NASM编译器生成的可执行文件大小。最后,利用Curses库设计了一个简单的弹球游戏,探讨了第三方库在代码设计中的应用。
摘要由CSDN通过智能技术生成

1. 静态库与动态库

1.1 准备工作

1.1.1新建main1.c、sub1.c、sub2.c文件
main1.csub1.c文件参考我之前的博客里面2.1.1和2.1.2编写即可
接下来新建sub2.c
输入命令:

touch sub2.c

即可创建一个名为sub2.c的文件
输入命令:

vim sub2.c

即可打开文件编辑

I开始在光标处插入
输入代码:

float x2y(int a,int b)
{
	float c;
	c=a+b;
	return c;
}

ESC回到命令模式
输入:wq退出vim编辑器并保存
至此3个 .c 文件已经准备完成

1.2 用gcc生成与使用静态库

1.2.1 用gcc生成.a静态库文件

要生成 .a 静态库文件首先要生成 .o 文件
输入命令:

gcc -c main1.c sub1.c sub2.c

即可生成main1.osub1.osub2.o
输入命令:

ar -crv libmysub.a sub1.o sub2.o

即可将sub1.osub2.o两个文件生成一个静态库文件libmysub.a

1.2.2 静态库的链接

输入命令:

gcc -o operation main1.o libmysub.a

即可生成可执行文件operation
输入命令:

./operation

运行结果如下:
在这里插入图片描述

1.3 用gcc生成与使用动态库

1.3.1用gcc生成.so动态库态库文件

前面已经生成了三个 .o文件,在此基础上
输入命令:

gcc -shared -fPIC -o libmysub.so sub1.o sub2.o

sub1.osub2.o生成一个动态库libmysub.so

1.3.2 动态库的链接

输入命令:

gcc main1.c libmysub.so -o operation1 

因为动态库的链接后要运行时程序要从目录 /usr/lib下找所以我们还需要把动态库文件libmysub.so移动到该文件夹内否则运行时会报错
错误如下:
在这里插入图片描述
解决错误:
输入命令:

mv libmysub.so /usr/lib

即可将动态库文件libmysub.so移动到目录 /usr/lib
(如果出现如下错误:
在这里插入图片描述
则是权限不够,只要进入管理员权限就好
输入命令:

sudo -s

再输入密码进入管理员权限之后执行上面移动命令即可
输入命令:

exit

即可退出管理员权限)
再次运行程序operation1
输入命令:

./operation1

结果如下:
在这里插入图片描述

1.4 静态库与动态库生成可执行文件对比

静态库:即静态链接库。以 .a为文件后缀名。在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库。
动态库:即动态链接库。以 .so 为文件后缀名。在程序编译时并不会被链接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
静态库代码装载的速度快,执行速度略比动态库快。但是动态库更加节省内存,可执行文件体积比静态库小很多。静态库是在编译时加载,动态库是在运行时加载。
对比如下:
operation为静态库生成可执行文件
operation1为动态库生成可执行文件
在这里插入图片描述
在这里插入图片描述

2. 编译器gcc与nasm编译的可执行文件大小的对比

2.1 准备文件hello.c和hello.asm

文件内容如下:
hello.c

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

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         ; 调用内核功能

2.2 分别用gcc和nadm编译文件

2.1.1 使用gcc编译

输入命令:

gcc hello.c

生成可执行文件a.out

2.2.2 使用nasm编译

(如果没有nasm编译器则需要先下载安装
输入命令:sudo apt install nasm
在这里插入图片描述
安装完成)

输入命令:

nasm -f elf64 hello.asm

生成hello.o文件
输入命令:

ld -s -o hello hello.o

生成可执行文件hello
分别运行用gcc编译的a.out和用nasm编译的hello
结果如下:
在这里插入图片描述

2.3 对比文件大小

输入命令:

size hello a.out

查看文件大小
在这里插入图片描述
显然nasm编译的可执行文件要比gcc编译的小很多

3. 借助第三方库函数完成代码设计

3.1 基于光标库(curses)的简单函数

3.1.1 在Ubuntu中安装curses库

输入命令:

sudo apt-get install libncurses5-dev 

即可
头文件默认位于 /usr/include
库文件默认位于 /usr/lib

3.1.2 使用curses库和其主要函数

需要加入头文件

#include <curses.h>

主要函数:

int insch(chtype ch);    //插入ch,右移
int insertln(void);    //插入空白行,下移
int delch(void);   //删除光标位置字符,左移
int deleteln(void)   //删除当前行,上移
int beep(void);     //发声
int flash(void);      //闪屏
int clrtobot(void);//清除光标位置到屏幕结尾的内容
int clrtoeol(void);//清除光标位置到该行行尾的内容

3.1.3 使用curses库例子

这里展示一个链接和使用光标库的游戏–弹球游戏
代码如下:

/*
 * 基于curses库弹球游戏,编译gcc xxx.c -lcurses
 */
#include <curses.h>
#include <sys/time.h>
#include <signal.h>
 
#define RIGHT COLS-1   /*球所能到达的当前屏幕最大水平范围*/
#define BOTTOM LINES-1 /*球所能到达的当前屏幕最大垂直范围*/
#define BOARD_LENGTH   10  /*挡板长度*/
#define LEFT 0  /*当前屏幕的最左边*/
#define TOP 0   /*当前屏幕的最上边*/
char BALL= 'O';  /*球的形状*/
char BLANK= ' ';  /*覆盖球走过的轨迹*/
 
 
int left_board; /*挡板左侧坐标*/
int right_board; /*挡板右侧坐标*/
int is_lose=0;
 
 
int hdir;   /*控制球水平运动的变量*/
int vdir;   /*控制球垂直运动的变量*/
int pos_X;  /*球的横坐标*/
int pos_Y;  /*球的纵坐标*/
      
int delay=100;
void moveBall();
void init();
void control();
 
int main()
{
    //初始化 curses
    initscr();
    crmode();  /*中断模式*/
    noecho();  /*关闭回显*/
     
    move(6,28);
    attron(A_BOLD);
    addstr("Welcome to the BallGame!");
    move(8,20);
    attroff(A_BOLD);
    addstr("Help:");
    move(9,23);
    addstr("'N':Start a new game.");
    move(10,23);
    addstr("'Q':Quit game.");
    move(11,23);
    addstr("'KEY_LEFT' :Control baffle left  shift.");
    move(12,23);
    addstr("'KEY_RIGHT':Control baffle right shift.");
    move(13,23);
    addstr("'KEY_UP'   :Control of the ball speed.");
    move(14,23);
    addstr("'KEY_DOWN' :Control of the ball reducer.");
    int flag=1;
    char choice;
    move(16,24);
    addstr("Please choose your choice!(n/q):");
    refresh();
    choice=getch();
    while(flag){
        if(choice=='q'||choice=='Q'||choice=='n'||choice=='N')
             flag=0;
        else  choice=getch();
    }
    if(choice=='n'||choice=='N'){    /*开始游戏*/
        clear();
        move(10,25);
        addstr("BallGame will start! Are you read?");
        refresh();
        sleep(3);
        control();
    }
    else if(choice=='q'||choice=='Q'){   /*退出游戏*/
        clear();
        move(10,25);
        addstr("You quit the game successfully!");
        refresh();
        sleep(3);
        endwin();
    }
    endwin();  /*结束 curses*/
    return 0;
}
 
void init(){
    int i,j;
    clear();
    if(start_color()==OK){  /*改变球和挡板的颜色*/
        attron(A_BOLD);  /*打开粗体*/
        init_pair(1,COLOR_YELLOW,COLOR_BLACK);
        attron(COLOR_PAIR(1));
    }
    //初始球
    pos_X =22;  /*球初始的横坐标*/
    pos_Y = BOTTOM-1;  /*球初始的纵坐标*/
    //初始化球的运动方向,朝右上方运动
    hdir=1; 
    vdir=-1;
 
    //初始挡板
    left_board=20;
    right_board=left_board+BOARD_LENGTH;
    for(i=left_board;i<=right_board;i++){  /*显示挡板*/
        move(BOTTOM,i);
        addch('-');
    }
 
    //初始刷新时间
    signal(SIGALRM,moveBall);
    set_ticker(delay);
 
    keypad(stdscr,TRUE);  /*打开 keypad 键盘响应*/
    attroff(A_BLINK);     /*关闭 A_BLINK 属性*/
     
    is_lose=0;
    move(pos_Y,pos_X);
    addch(BALL);
    move(LINES-1, COLS-1);
    refresh();
    usleep(100000);  /*睡眠*/
    move(LINES-1,COLS-1);
    refresh();
}
 
void moveBall(){
    if(is_lose) return;
    signal(SIGALRM,moveBall);
    move(pos_Y,pos_X);
    addch(BLANK);
    pos_X += hdir;
    pos_Y += vdir;
    //改变球的方向时
    if(pos_X >= RIGHT) { /*当球横坐标大于右边边缘时,球反弹朝左运动*/
        hdir = -1;
        beep();   /*球撞墙时,发出声音*/
    }
    if(pos_X <= LEFT)  { /*当球横坐标大于左边边缘时,球反弹朝右运动*/
        hdir = 1;
        beep();  /*球撞墙时,发出声音*/
    }
    if(pos_Y <= TOP)   { /*当球纵坐标大于顶部边缘时,球反弹朝下运动*/
        vdir = 1;
        beep();  /*球撞墙时,发出声音*/
    }
 
    //当球在底部的时候进行额外的处理
    if(pos_Y >= BOTTOM-1){
        if(pos_X>=left_board&&pos_X<=right_board)  /*球在挡板处*/
            vdir=-1;
        else{    /*球不在挡板处*/
            is_lose=1;
            move(pos_Y,pos_X);
            addch(BALL);
            move(LINES-1, COLS-1);
            refresh();
            usleep(delay*1000);  /*睡眠*/
            move(pos_Y,pos_X);
            addch(BLANK);
            pos_X += hdir;
            pos_Y += vdir;
            move(pos_Y,pos_X);
            addch(BALL);
            move(LINES-1, COLS-1);
            refresh();
        }
    }
    //不改变球的方向时
    move(pos_Y,pos_X);
    addch(BALL);
    move(LINES-1, COLS-1);
    refresh();
}
void control(){
    init();
    int cmd;
    while (1)
    {     
        if(!is_lose){
            cmd=getch();
            if(cmd=='q'||cmd=='Q'||cmd==27) break;  //强制退出游戏
            //挡板左移
            if(cmd==KEY_LEFT){
                if(left_board>0){
                    move(BOTTOM,right_board);
                    addch(' ');
                    right_board--;
                    left_board--;                     
                    move(BOTTOM,left_board);
                    addch('-');
                    move(BOTTOM,RIGHT);
                    refresh();
                }
            }     
            //挡板右移
            else if(cmd==KEY_RIGHT){
                if(right_board<RIGHT){
                    move(BOTTOM,left_board);
                    addch(' ');
                    right_board++;
                    left_board++;
                    move(BOTTOM,right_board);
                    addch('-');
                    move(BOTTOM,RIGHT);
                    refresh();
                }
            }
            //给球加速
            else if(cmd==KEY_UP){   
                delay/=2;     
                set_ticker(delay);
            }
            //给球减速
            else if(cmd==KEY_DOWN){  
                delay*=2;
                set_ticker(delay);
            }
         
        }
        else{
            //输掉球后的处理
            int flag=1;
            char choice;
            move(8,15);
            addstr("Game Over!try again?(y/n):");
            refresh();
            choice=getch();
 
            while(flag){
                if(choice=='y'||choice=='Y'||choice=='n'||choice=='N')
                     flag=0;
                else  choice=getch();
            }
            if(choice=='y'||choice=='Y'){  /*游戏重新开始*/
                    delay=100; /*恢复球的初始速度*/
                    init();
                    continue;
            }
            else if(choice=='n'||choice=='N'){   /*结束游戏*/
                    break;
            }
        }
    }
}
//设置定时器
int set_ticker(int n_msecs){
    struct itimerval new_timeset;     
    long n_sec,n_usecs;
    n_sec=n_msecs/1000;
    n_usecs=(n_msecs%1000)*1000L;
    new_timeset.it_interval.tv_sec=n_sec;
    new_timeset.it_interval.tv_usec=n_usecs;
    new_timeset.it_value.tv_sec=n_sec;
    new_timeset.it_value.tv_usec=n_usecs;
    return setitimer(ITIMER_REAL,&new_timeset,NULL); 
}

(代码来源于博客curses库实现的弹球游戏
编译执行结果如下:
在这里插入图片描述
在这里插入图片描述

3.2 体验远古时代的 BBS (一个用键盘光标控制的终端程序)

在 win10 系统中,“控制面板”–>“程序”—>“启用或关闭Windows功能”,启用 “telnet client” 和"适用于Linux的Windows子系统"。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,以游客身份体验一下即将绝迹的远古时代的 BBS (一个用键盘光标控制的终端程序)。
结果如下:
在这里插入图片描述
在这里插入图片描述

4. 总结

通过以上,了解编译器背后的故事知道到静态库和动态库在程序运行时的区别以及优缺点,不同编译器的区别比如nasm和gcc以及了解如何借助第三方库函数完成代码设计。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值