Linux系统编译器

可执行程序组装流程

1.先通过代码编写一个源程序。
2.将源程序进行预编译。
3.将预编译生成的文件进行编译。
4.汇编,将代码变成机器可以执行的指令。
5.链接。

Linux下静态库.a与.so库文件的的生成与使用

1.创建作业目录并打开

jzddyy@ubuntu:~$ mkdir test2
jzddyy@ubuntu:~$ cd test2

在这里插入图片描述
2.用nano编辑器生成四个文件A1.c,A2.c,A.h,test.c。
A1.c

#include <stdio.h>
void print1(int arg)
{
printf("A1 print arg:%d\n",arg);
}

A2.c

#include<stdio.h>
void print2(char *arg)
{
printf("A2 printf arg:%s\n",arg);
}

A.h

#ifndef A_H
#define A_H
void print1(int);
void print2(char *);
#endif

test.c

#include <stdio.h>
#include "A.h"
int main()
{
print1(1);
print2("test");
exit(0);
}

生成四个文件如下
在这里插入图片描述
3.静态库.a文件的生成与使用
3.1生成.o目标文件

jzddyy@ubuntu:~/test2$ gcc -c A1.c A2.c

在这里插入图片描述
3.2生成静态.a文件

jzddyy@ubuntu:~/test2$ ar crv libafile.a A1.o A2.o
a - A1.o
a - A2.o

在这里插入图片描述
3.3创建可执行程序

jzddyy@ubuntu:~/test2$ gcc -o test test.c libafile.a
jzddyy@ubuntu:~/test2$ ./test
A1 print arg:1
A2 printf arg:test

在这里插入图片描述
4.共享库.so文件的生成与使用
生成目标文件、生成共享库.so文件、使用.so文件创建可执行程序

gcc -c -fpic A1.c A2.c
jzddyy@ubuntu:~/test2$ gcc -shared *.o -o libsofile.so
jzddyy@ubuntu:~/test2$ gcc -o test test.c libsofile.so

出现错误

zddyy@ubuntu:~/test2$ ./test
./test: error while loading shared libraries: libsofile.so: cannot open shared object file: No such file or directory

将.so拷贝到对应路径并运行

jzddyy@ubuntu:~/test2$ sudo cp libsofile.so/usr/lib
jzddyy@ubuntu:~/test2$ ./test

用gcc生成.a静态库和.so动态库

1.编辑生成例子程序hello.h、hello.c、main.c
创建作业目录

jzddyy@ubuntu:~/test2$ mkdir test1
jzddyy@ubuntu:~/test2$ cd test1

hello.h

#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif//HELLO_H

hello.c

#include<stdio.h>
void hello(const char *name)
{
printf("Hello%s!\n",name);
}

main.c

#include"hello.h"
int main()
{
hello("everyone");
return 0;
}

2.将hello.c编译成.o文件

jzddyy@ubuntu:~/test2/test1$ gcc -c hello.c
jzddyy@ubuntu:~/test2/test1$ ls
hello.c  hello.h  hello.o  main.c

3.由.o文件创建静态库

jzddyy@ubuntu:~/test2/test1$ ar -crv libmyhello.a hello.o
a - hello.o
jzddyy@ubuntu:~/test2/test1$ ls
hello.c  hello.h  hello.o  libmyhello.a  main.c
jzddyy@ubuntu:~/test2/test1$ 

4.在程序中使用静态库

jzddyy@ubuntu:~/test2/test1$ gcc -o hello main.c -L. -lmyhello

5.由.o文件创建动态库文件

jzddyy@ubuntu:~/test2/test1$ gcc -shared -fPIC -o libmyhello.so hello.o
jzddyy@ubuntu:~/test2/test1$ ls
hello  hello.c  hello.h  hello.o  libmyhello.a  libmyhello.so  main.c

6.在程序中使用动态库

jzddyy@ubuntu:~/test2/test1$ gcc main.c libmyhello.so -o hello
jzddyy@ubuntu:~/test2/test1$ ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

出现错误,执行如下操作

jzddyy@ubuntu:~/test2/test1$ mv libmyhello.so/usr/lib

编写一个x2y函数并实现上述操作

1.x2y函数如下

#include<stdio.h>
float x2y(int a,int b)
{float c;
c=a*b;
return c;
}

2.用gcc编译为3个目标文件

jzddyy@ubuntu:~$ gcc -c main1.c
jzddyy@ubuntu:~$ gcc -c sub1.c
jzddyy@ubuntu:~$ gcc -c sub2.c
jzddyy@ubuntu:~$ ls
1.sh       examples.desktop  main1.c.save  Pictures  sub1.o     test2
Desktop    hello             main1.o       Public    sub2.c     Videos
Documents  main1             makefile      snap      sub2.o
Downloads  main1.c           Music         sub1.c    Templates

3.将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件

jzddyy@ubuntu:~$ ar -crv myword.a sub1.o sub2.o
a - sub1.o
a - sub2.o
jzddyy@ubuntu:~$ ls
1.sh       examples.desktop  main1.c.save  myword.a  sub1.c  Templates
Desktop    hello             main1.o       Pictures  sub1.o  test2
Documents  main1             makefile      Public    sub2.c  Videos
Downloads  main1.c           Music         snap      sub2.o

4.链接生成可执行文件并记录大小

jzddyy@ubuntu:~$ gcc main1.c myword.a -o myword
jzddyy@ubuntu:~$ ./myword
请输入两个数
4
5
两个数相除得0.8000
两个数相乘得20.000000
jzddyy@ubuntu:~$ size myword
   text	   data	    bss	    dec	    hex	filename
   2165	    624	      8	   2797	    aed	myword

5.将x2x、x2y目标文件用 ar工具生成1个 .a 动态库文件

jzddyy@ubuntu:~$ gcc -shared -fPIC -o myword.so sub1.o sub2.o
jzddyy@ubuntu:~$ gcc -o myword main1.c -L.-myword

gcc中EFF文件格式、汇编语言格式

1.gcc常用命令
示例程序

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

(1)编译指令(预处理、编译、汇编、链接)

gcc test.c -o test

预处理

gcc -E test.c -o test.i

编译

jzddyy@ubuntu:~$ gcc -S test.i -o test.s

汇编

jzddyy@ubuntu:~$ gcc -c test.s -o test.o

链接

jzddyy@ubuntu:~$ gcc test.o -o test

2.多个程序文件的编译

gcctest1.ctest2.c-o test

以上代码等效于以下代码

gcc -c test1.c -o test1.o 
gcc -c test2.c -o test2.o 
gcc test1.o test2.o -o test

3.检错

gcc -pedantic illcode.c -o illcode
gcc -Wall illcode.c -o illcode

gcc在警告的地方停止编译

gcc -Werror test.c -o test

gcc编译器

1.编写一个简单的输出hello文件

#include <stdio.h> //此程序很简单,仅仅打印一个 Hello World 的字符串。 
int main(void) 
{ printf("Hello World! \n"); return 0; }

2.用gcc预处理生成.i文件

gcc -E hello.c -o hello.i

3.使用 gcc 进行编译

gcc -S hello.i -o hello.s 

4.使用gcc进行汇编

 gcc -c hello.s -o hello.o 

5.链接并查看大小

gcc hello.c -o hello 
size hello

nasm安装与使用

在这里插入图片描述
在这里插入图片描述

第三方库函数

1.基本函数功能名称介绍

echochar(ch):显示某个字元
addch(ch):显示某个字元
addstr(str):显示一串字串
move(y,x):将游标移动至x,y的位置
getyx(win,y,x):得到目前游标的位置

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

贪吃蛇游戏测试

//mysnake1.0.c
//编译命令:cc mysnake1.0.c -lcurses -o mysnake1.0
//用方向键控制蛇的方向
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#define NUM 60

struct direct                //用来表示方向的
{
    int cx;
    int cy;
};
typedef struct node            //链表的结点
{
    int cx;
    int cy;
    struct node *back;
    struct node *next;
}node;

void initGame();            //初始化游戏
int setTicker(int);            //设置计时器
void show();                //显示整个画面
void showInformation();        //显示游戏信息(前两行)
void showSnake();            //显示蛇的身体
void getOrder();            //从键盘中获取命令
void over(int i);            //完成游戏结束后的提示信息

void creatLink();                //(带头尾结点)双向链表以及它的操作
void insertNode(int x, int y);   
void deleteNode();
void deleteLink();

int ch;                                //输入的命令
int hour, minute, second;            //时分秒
int length, tTime, level;            //(蛇的)长度,计时器,(游戏)等级
struct direct dir, food;            //蛇的前进方向,食物的位置
node *head, *tail;                    //链表的头尾结点

int main()
{
    initscr();
    initGame();
    signal(SIGALRM, show);
    getOrder();
    endwin();
    return 0;
}

void initGame()
{
    cbreak();                    //把终端的CBREAK模式打开
    noecho();                    //关闭回显
    curs_set(0);                //把光标置为不可见
    keypad(stdscr, true);        //使用用户终端的键盘上的小键盘
    srand(time(0));                //设置随机数种子
    //初始化各项数据
    hour = minute = second = tTime = 0;
    length = 1;
    dir.cx = 1;
    dir.cy = 0;
    ch = 'A';
    food.cx = rand() % COLS;
    food.cy = rand() % (LINES-2) + 2;
    creatLink();
    setTicker(20);
}

//设置计时器(这个函数是书本上的例子,有改动)
int setTicker(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;      
    n_msecs = 1;
    n_sec = n_msecs / 1000 ;
    n_usecs = ( n_msecs % 1000 ) * 1000L ;
    new_timeset.it_value.tv_sec     = n_sec  ;      
    new_timeset.it_value.tv_usec    = n_usecs ;     
    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

void showInformation()
{
    tTime++;
    if(tTime >= 1000000)                //
        tTime = 0;
    if(1 != tTime % 50)
        return;
    move(0, 3);   
    //显示时间
    printw("time: %d:%d:%d %c", hour, minute, second);
    second++;
    if(second > NUM)
    {
        second = 0;
        minute++;
    }
    if(minute > NUM)
    {
        minute = 0;
        hour++;
    }
    //显示长度,等级
    move(1, 0);
    int i;
    for(i=0;i<COLS;i++)
        addstr("-");
    move(0, COLS/2-5);
    printw("length: %d", length);
    move(0, COLS-10);
    level = length / 3 + 1;
    printw("level: %d", level);
}

//蛇的表示是用一个带头尾结点的双向链表来表示的,
//蛇的每一次前进,都是在链表的头部增加一个节点,在尾部删除一个节点
//如果蛇吃了一个食物,那就不用删除节点了
void showSnake()
{
    if(1 != tTime % (30-level))
        return;
    //判断蛇的长度有没有改变
    bool lenChange = false;
    //显示食物
    move(food.cy, food.cx);
    printw("@");
    //如果蛇碰到墙,则游戏结束
    if((COLS-1==head->next->cx && 1==dir.cx)
        || (0==head->next->cx && -1==dir.cx)
        || (LINES-1==head->next->cy && 1==dir.cy)
        || (2==head->next->cy && -1==dir.cy))
    {
        over(1);
        return;
    }
    //如果蛇头砬到自己的身体,则游戏结束
    if('*' == mvinch(head->next->cy+dir.cy, head->next->cx+dir.cx) )
    {
        over(2);
        return;
    }
    insertNode(head->next->cx+dir.cx, head->next->cy+dir.cy);
    //蛇吃了一个“食物”
    if(head->next->cx==food.cx && head->next->cy==food.cy)
    {
        lenChange = true;
        length++;
        //恭喜你,通关了
        if(length >= 50)
        {
            over(3);
            return;
        }
        //重新设置食物的位置
        food.cx = rand() % COLS;
        food.cy = rand() % (LINES-2) + 2;
    }
    if(!lenChange)
    {
        move(tail->back->cy, tail->back->cx);
        printw(" ");
        deleteNode();
    }
    move(head->next->cy, head->next->cx);
    printw("*");
}

void show()
{
    signal(SIGALRM, show);        //设置中断信号
    showInformation();
    showSnake();
    refresh();                    //刷新真实屏幕
}

void getOrder()
{
    //建立一个死循环,来读取来自键盘的命令
    while(1)
    {
        ch = getch();
        if(KEY_LEFT == ch)
        {
            dir.cx = -1;
            dir.cy = 0;
        }
        else if(KEY_UP == ch)
        {
            dir.cx = 0;
            dir.cy = -1;
        }
        else if(KEY_RIGHT == ch)
        {
            dir.cx = 1;
            dir.cy = 0;
        }
        else if(KEY_DOWN == ch)
        {
            dir.cx = 0;
            dir.cy = 1;
        }
        setTicker(20);
    }
}

void over(int i)
{
    //显示结束原因
    move(0, 0);
    int j;
    for(j=0;j<COLS;j++)
        addstr(" ");
    move(0, 2);
    if(1 == i)
        addstr("Crash the wall. Game over");
    else if(2 == i)
        addstr("Crash itself. Game over");
    else if(3 == i)
        addstr("Mission Complete");
    setTicker(0);                //关闭计时器
    deleteLink();                //释放链表的空间
}

//创建一个双向链表
void creatLink()
{
    node *temp = (node *)malloc( sizeof(node) );
    head = (node *)malloc( sizeof(node) );
    tail = (node *)malloc( sizeof(node) );
    temp->cx = 5;
    temp->cy = 10;
    head->back = tail->next = NULL;
    head->next = temp;
    temp->next = tail;
    tail->back = temp;
    temp->back = head;
}

//在链表的头部(非头结点)插入一个结点
void insertNode(int x, int y)
{
    node *temp = (node *)malloc( sizeof(node) );
    temp->cx = x;
    temp->cy = y;
    temp->next = head->next;
    head->next = temp;
    temp->back = head;
    temp->next->back = temp;
}

//删除链表的(非尾结点的)最后一个结点
void deleteNode()
{
    node *temp = tail->back;
    node *bTemp = temp->back;
    bTemp->next = tail;
    tail->back = bTemp;
    temp->next = temp->back = NULL;
    free(temp);
    temp = NULL;
}

//删除整个链表
void deleteLink()
{
    while(head->next != tail)
        deleteNode();
    head->next = tail->back = NULL;
    free(head);
    free(tail);
}

运行后的程序如下图所示(如果运行不成功,可添加#include<time.h>)
在这里插入图片描述

总结

这次的实验比较有趣,让我们更深入的了解了Linux的各种命令,对比了解了静态库和动态库之间的联系,区别,也让我们体验了利用代码实现简单游戏的乐趣。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值