一、环境介绍

我目前使用的是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是说明编译器寻找库的位置,‘.’代表了当前文件夹,如果在别的文件夹寻找,则可以用正常的地址说明(比如‘..’代表上一个文件夹,别的的话可以用绝对地址和相对地址)。最后如果你要使用动态库的话,就自己左转百度吧,因为那个用起来比较麻烦,需要设置系统的寻找路径,如果只是简单的程序,静态库就足够了。

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

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文件,下一节讲)

23333.png

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

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

  1. linux 网络冲浪,命令行下的网络冲浪工具命令行浏览器介绍

    Linux命令行是强大的工具,命令行是我们的日常工作,命令行更是我们日常生活.之前虫虫给大家写过一些命令的的介绍,命令行的工具,命令行下的开发.实际上命令行也是我们不可或缺的生活.本文我们来介绍一下命 ...

  2. linux添加触摸屏,Linux_Linux系统下触摸屏的简单使用和配置方法, 如果你装的是 Ubuntu 发行 - phpStudy...

    Linux系统下触摸屏的简单使用和配置方法 如果你装的是 Ubuntu 发行版,那么基本上你的 X 的配置文件 (xorg.conf) 里面已经设置好了相关的驱动,是默认设置,你只需要添加些相关的参数 ...

  3. 查看linux系统版本centos,CentOS下查看系统版本的4种方法

    Linux有很多的发行版,不同的版本会有一些细微区别,所以经常需要查看服务器系统的版本号. 下面来看下CentOS下如何查看CentOS版本. 方法1:cat /etc/issue 执行命令:[www ...

  4. linux新增mysql用户_linux下mysql创建新的用户的方法

    1.以root身份登录到MySQL服务器中. $ mysql -u root -p 当验证提示出现的时候,输入MySQL的root帐号的密码. 2.创建一个MySQL用户 使用如下命令创建一个用户名和 ...

  5. debian 编译linux内核源码,Debian下为本机编译内核模块的方法

    改用Debian之后发现用之前在Red Hat下编译内核模块的Makefile不好使了,原因是在/lib/modules/`uname -r`/下没有了build目录,也没有内核的源代码.上网查了一些 ...

  6. linux shell读取文件,shell下同时读取多个文件的方法

    1. 单个文件的读取 在shell脚本下,可以多种方式实现按行读取文件,如下: for line in `cat ${input_filename}` do echo $line done while ...

  7. Linux 环境下的抓包工具 - tcpdump

    Linux 环境下,通常通过 tcpdump 来进行抓包和分析.它是几乎所有 Linux 发行版本预装的数据包抓取和分析工具. 一.tcpdump 的用法 tcpdump [-aAbdDefhHIJK ...

  8. linux c语言工具,Linux下C语言编程环境的工具.doc

    Linux下C语言编程环境的工具 Linux下C语言编程环境的工具 Linux下C语言编程环境的工具 要想在Linux下进行C语言编程,首先得搭建好一个编程环境.这里分别说明一下几个非常有用的软件包. ...

  9. SIPp工具Linux下安装

    2019独角兽企业重金招聘Python工程师标准>>> 一.SIPp介绍 SIPp是一个测试SIP协议性能的工具软件,这是一个开源软件.      它可使用INVITE和B YE建立 ...

  10. Linux下的数据备份工具rsync

    Linux下的数据备份工具很多,用得最多的是rsyns(远程同步) 同步远程数据类似scp 同步本地数据类似cp root@ip-172-31-8-212:~# rsync /etc/passwd / ...

最新文章

  1. 我用分布式事务干掉了一摞简历
  2. Oracle DBMS_STATS 包 和 Analyze 命令的区别
  3. 从JS对象开始,谈一谈“不可变数据”和函数式编程
  4. java8 parallelStream性能测试
  5. redis常用命令_Redis的简介以及基本常用命令
  6. 学习笔记2-Linux2
  7. java中找不到javax包_logstash 找不到 java 环境
  8. 如何在MATLAB中定义一些全局常量
  9. java 分级显示_上级部门与下级部门的分类显示
  10. css flex布局 padding,css三栏布局的三种实现方式(圣杯布局、双飞翼布局、Flex布局)...
  11. LigerUI学习使用
  12. pycharm不能输入代码
  13. 深入学习理解UNIX网络编程
  14. android高仿朋友圈,高仿微信朋友圈图片展示效果 ImageWatcher
  15. Pssp-mvirt: 基于多视图深度学习架构的肽二级结构预测
  16. 给大家介绍六个不错的数据分析工具
  17. 微信小程序 Unexpected token in JSON at position 0 设置二维码,并且使用js中JSON.parse()函数将二维码返回的值转化为json格式
  18. 机器学习——支持向量机——硬间隔与支持向量
  19. python的continue用法_Python学习笔记之Break和Continue用法分析
  20. 1.8 Illustrator标尺的使用 [Illustrator CC教程]

热门文章

  1. HTML自动填充表格,word文档中如何实现表格自动填充
  2. 使用代理服务器是否安全?
  3. 前端花瓣飘落特效代码
  4. 写给安卓软件工程师的3条建议,全套教学资料
  5. HTML做一个节日页面【六一儿童节】纯HTML代码
  6. python nan变成0_python nan怎么解决
  7. 普通文本与富文本,超文本之间的区别
  8. 【理解】运用数据透视表制作三栏账
  9. linux 运行.deb,Ubuntu下如何用命令行运行deb安装包
  10. 16比9尺寸是多少厘米_16比9尺寸换算方法