如何给linux预装一些工具,linux 下的一些基本工具的使用方法

一、环境介绍

我目前使用的是ubuntu的16.04版本,所以的话这篇文章所有的截图都来自于ubuntu下的终端,个人的话推荐不要装16.04,或者说不要装ubuntu,centos相对于它更加稳定(前提是你能够接受那种丑爆了的桌面)。我用ubuntu的时候wifi就经常炸,各种奇葩的连不上或者说一直连,然后还是连不上。

这个时候推荐使用下面的命令:

sudo service network-manager restart```

不过这个命令有时候还是不好使,所以只能是重启,总的来说这就很尴尬了,所以大家懂的···

##二、编译器

***

gcc是linux下自带的编译器,其功能可以说很强大,可以编译c,c++,java等多门语言,不过这里我讲的是关于c语言编译的时候的一些使用方法。在此之前,你至少需要知道下面的一些基本知识,然后后面的一些命令才好进行讲解。

#####(一)基础知识

- 从你写好的代码到生成最终的可运行文件,大致分为以下几步:

- 对源文件进行预处理,处理除#pragma以外以#号开头的命令,去除文件中的空格,注释,添加行号和文件标识(在生成调试文件时有用)。

- 对处理过的文件进行编译,对语法进行解析,在进行相应的优化后,生成汇编代码,但是生成的是AT&T语法格式的汇编代码,而不是intel的。

- 将汇编代码通过几乎是直接翻译的方式生成机器码,然后你打开文件就会看到一堆二进制码。

- 最后一步链接,就是将生成的二进制文件与静态库链接或者做动态库的链接标记。如果说没有自己创建库文件,这一步可以由编译器自动完成。

- 库文件

- 库文件分为静态库和动态库。

- 库文件在linux下为.a或.so文件,它们的名字以lib开头,是经过编译了的源文件,它在生成时需要有一个头文件(.h)标注其所含有的函数以及这些函数的类型定义,同时需要有一个源文件(.c),实现所有的函数。比如:

calc.h:

double aver(double, double);

double sum(double, double);```

calc.c:

double aver(double num1, double num2)

{

return (num1+num2)/2;

}

double sum(double num1, double num2)

{

return num1+num2;

}```

- 静态库在编译的时候会把代码放入程序中,而动态库则是在程序中留下调用的链接,等到程序运行的时候再将动态库加载进入内存进行使用,所以对于同样的程序,使用动态库会使程序文件本身占空间更少。

- 动态库可以多个程序共用,而只占一份的空间。而静态库本身是不共享的,也就是说一个程序要使用,就要自己留有一份代码。

- gcc编译器可以控制编译的过程,通过在终端(terminal)中输入不同的命令,可以生成从源文件到可运行程序间的各种文件。

- .s汇编语言文件

- .o二进制文件

- .i仅仅进行预处理的文件

- .a静态库文件

- .so动态库文件

#####(二)gcc基础命令

gcc的命令超过了100条,所以这里仅仅只是列举一些常常用到的命令,其余的命令会在后面需要时再列举。这里我用到了一个很简单的hello.c作为例子进行讲解。

include

int main()

{

printf("hello world");

return 0;

}```

直接生成一个可以运行的文件

gcc hello.c```

这个时候你应该可以在当前的目录下找到a.out文件,因为在命令中没有指定最终生成的文件名,所以会输出一个带有默认文件名的文件。如果你想指定生成文件的名字,可以用-o命令。

gcc hello.c -o hello```

这样就可以生成一个hello的可运行程序,最后你需要做的就是再输入下面的命令让程序运行起来。

./hello```

- 生成一个仅仅进行过预处理的文件

gcc -E hello.c -o hello.i```

这里的-E命令告诉编译器在预处理后就停止,至于hello.i你可以改成别的名字,只是一般习惯于把预处理文件的后缀名命名为i。这个时候打开文件,你可以看到所有的stdio.h中的内容都导入到了hello.i中。

对预处理过的文件进行编译

gcc -S hello.i -o hello.s```

这里注意是大写的S,等你再次打开文件的时候,熟悉的c代码就变成了汇编代码,同样的,.s文件常常表示汇编语言文件。

- 将汇编代码翻译为二进制代码

gcc -c hello.s -o hello.o```

这个时候你写的源文件的转换就已经结束了,但是这个时候的文件还不能使用,因为这个文件还没有和库文件进行链接,许许多多的函数在头文件中只有定义,如果你要使用这些函数,就需要与动态库或者静态库进行链接。

进行链接

gcc hello.o -o hello```

将二进制文件链接,最终生成可以运行的hello文件。

实际上,如果你只想要自定义链接过程,你可以从源文件开始,直接生成没有链接的二进制文件,命令和上面的差不多

gcc -c hello.c -o hello.o```

上面的命令包括-c -E -S其实都是停止命令,意思是告诉编译器在某一步骤停下来,所以说gcc会自动判断目前文件所在的步骤,你需要做的就是告诉编译器怎么停下来。

(三)动态库和静态库

这里主要是讲在编译的时候使用库文件,制作库文件只是简单说一下,制作静态库和动态库的制作和gcc的关系并不是很大。如果你要生成静态库,你需要的东西有:你的.o文件和库的头文件。然后你需要运行的命令如下:

ar rc libmylib.a mylib.o```

如果你的库文件由多个.o文件组成,你只需要把.o文件都列出来就ok了

ar rc libmylib.a mylib1.o mylib2.o```

完成后你的目录下就会生成一个libmylib.a的文件,需要注意到的是,不论是动态库还是静态库都需要以lib作为命名的前缀。然后生成动态库的命令要稍微长一些:

gcc -shared -o libmylib.somylib1.o mylib2.o```

说完了怎么制作,就要说说怎么用了,如果你要使用静态库,那么原本的编译命令中仅仅需要加上几个字母:

gcc test.c -lmylib -L . -o test```

需要注意的是第一个-l是库名,但是省略了lib这个前缀和.a的扩展名,第二个-L是说明编译器寻找库的位置,‘.’代表了当前文件夹,如果在别的文件夹寻找,则可以用正常的地址说明(比如‘..’代表上一个文件夹,别的的话可以用绝对地址和相对地址)。最后如果你要使用动态库的话,就自己左转百度吧,因为那个用起来比较麻烦,需要设置系统的寻找路径,如果只是简单的程序,静态库就足够了。

下面是我做的一个简单的例子,演示了上面的过程,代码拙劣,希望不要笑话我(我只是个学生),当然有什么建议还是希望指出。

18d811cfafcf

2333.png

这个是最早的三个源文件

stack.h是用来后期给引用库文件的程序include的,里面存放了函数的原型和数据结构

stack.h

#pragma once

#ifndef STACK_INTERFACE

#define STACK_INTERFACE

typedef struct {

char *base;

char *top;

int stack_size;

int ele_size;

}Stack;

Stack* stackInit(int ele_size);

int stackDes(Stack *stack);

int stackPop(Stack *stack, void *value);

int stackPush(Stack *stack, void *value);

int stackGetTop(Stack *stack,void *value);

int stackEleNum(Stack *stack);

#endif

stackBase.h主要是存放了一些基本定义和宏函数

stackBase.h

//基本定义

#include

#include

#pragma once

#ifndef JUDGEMENT

#define JUDGEMENT

#define YES 1;

#define NO 0;

#endif

#ifndef STACK_ERROR

#define STACK_ERROR

#define OVERFLOW -1

#define STACK_EMPTY -2

#endif

#ifndef STACK_INI

#define STACK_INI

#define STACK_INIT_SIZE 40

#define STACK_INCREMENT_SIZE 40

#endif

#ifndef STACK_STRUCT

#define STACK_STRUCT

typedef struct {

char *base;

char *top;

int stack_size;

int ele_size;

}Stack;

#endif

stackBase.h

//用于扩展栈的大小

#ifndef STACK_BASE_FUNC

#define STACK_BASE_FUNC

/*

*@param char* _INCRE_BASE_

*@param char* _INCRE_TOP_

*@param int _INCRE_STACK_SIZE_

*@param int _INCRE_STACK_ELE_SIZE_

*

*/

#define stackIncre(_INCRE_BASE_, _INCRE_TOP_, _INCRE_STACK_SIZE_, \

_INCRE_STACK_ELE_SIZE_) \

({ \

int _INCRE_RETURN_; \

_INCRE_BASE_ = realloc(_INCRE_BASE_, _INCRE_STACK_SIZE_ + \

STACK_INCREMENT_SIZE * _INCRE_STACK_ELE_SIZE_); \

if(_INCRE_BASE_) { \

_INCRE_TOP_ = _INCRE_BASE_ + _INCRE_STACK_SIZE_; \

_INCRE_STACK_SIZE_ += STACK_INCREMENT_SIZE * \

_INCRE_STACK_ELE_SIZE_; \

_INCRE_RETURN_ = 0; \

} else { \

_INCRE_RETURN_ = OVERFLOW; \

} \

_INCRE_RETURN_; \

})

stackBase.h

//检查栈是否为空

/*

*@param char* _EMPTY_BASE_

*@param char* _EMPTY_TOP_

*

*/

#define stackEmpty(_EMPTY_BASE_, _EMPTY_TOP_) \

({ \

(_EMPTY_BASE_ == _EMPTY_TOP_) ? 1 : 0; \

})

stackBase.h

//检查栈是否已满

/*

*@param char* _FULL_BASE_

*@param char* _FULL_TOP_

*@param int _FULL_STACK_SIZE_

*

*/

#define stackFull(_FULL_BASE_, _FULL_TOP_, _FULL_STACK_SIZE_) \

({ \

(_FULL_TOP_ - _FULL_BASE_ == _FULL_STACK_SIZE_) ? 1 : 0; \

})

#endif

stackBase.h

//向栈中插入数据

#ifndef DATA_HANDLE

#define DATA_HANDLE

/*

* Insert data into stack.

*

* @param char* _IN_TOP_

* @param char* _IN_DATA_

* @param int _IN_ELE_SIZE_

*

*/

#define stackDataIn(_IN_TOP_, _IN_DATA_, _IN_ELE_SIZE_) \

do { \

int _IN_TEMP_COUNT_ = 0; \

while(_IN_TEMP_COUNT_++ < _IN_ELE_SIZE_) { \

*(_IN_TOP_)++ = *(_IN_DATA_)++; \

} \

} while(0)

stackBase.h

//删除栈中的数据

/*

* Delete data from stack

*

* @param char* _OUT_TOP_

* @param char* _OUT_DATA_

* @param int _OUT_ELE_SIZE_

*

*/

#define stackDataOut(_OUT_TOP_, _OUT_DATA_, _OUT_ELE_SIZE_) \

do { \

int _OUT_TEMP_COUNT_ = 0; \

(_OUT_DATA_) += _OUT_ELE_SIZE_; \

while(_OUT_TEMP_COUNT_++ < _OUT_ELE_SIZE_) { \

*--(_OUT_DATA_) = *--(_OUT_TOP_); \

} \

} while(0)

#endif

最后的.c文件放了真正的函数

stackInterface.c

#include "stackBase.h"

//初始化一个栈

Stack* stackInit(int ele_size)

{

Stack *init = (Stack *)malloc(sizeof(Stack));

if(init->base = (char *)malloc(ele_size * STACK_INIT_SIZE)) {

init->stack_size = ele_size * STACK_INIT_SIZE;

init->top = init->base;

init->ele_size = ele_size;

} else {

init->top = init->base = 0;

init->stack_size = 0;

init->ele_size = 0;

}

return init;

}

stackInterface.c

//将元素出栈

int stackPop(Stack *stack, void *value)

{

char *cvalue = (char *)value;

int empty = stackEmpty(stack->base, stack->top);

if(empty) {

return STACK_EMPTY;//stack_empty

}

stackDataOut(stack->top, cvalue, stack->ele_size);

return 0;

}

stackInterface.c

//将元素入栈

int stackPush(Stack *stack, void *value)

{

char *cvalue = (char *)value;

if(stackFull(stack->base, stack->top, stack->stack_size)) {

if(stackIncre(stack->base, stack->top, stack->stack_size, stack->ele_size)) {

return OVERFLOW;

}

}

stackDataIn(stack->top, cvalue, stack->ele_size);

return 0;

}

stackInterface.c

//获取栈顶元素而不出栈

int stackGetTop(Stack *stack, void *value)

{

char *cvalue = (char *)value;

if(stackEmpty(stack->base, stack->top)) {

return STACK_EMPTY;//stack_empty

}

stackDataOut(stack->top, cvalue, stack->ele_size);

stack->top += stack->ele_size;

return 0;

}

//释放栈空间

void stackDes(Stack *stack)

{

free(stack->base);

stack->base = stack->top = 0;

stack->stack_size = 0;

}

//计数栈中元素的个数

int stackEleNum(Stack *stack)

{

return (stack->top - stack->base) / stack->ele_size;

}

这些代码写完了之后,依次使用如下的命令

gcc -c stackInterface.c -O2

ar rc libstack.a stackInterface.o

就会生成一个静态库(不要在意Makefile文件,下一节讲)

18d811cfafcf

23333.png

然后如果哪一天要用到这个库了,记得在程序里面包含stack.h这个头文件然后按照上面的命令就ok了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值