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 <stdio.h>

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 <stdio.h>
#include <stdlib.h>

#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了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容