美文网首页
linux 下的一些基本工具的使用方法

linux 下的一些基本工具的使用方法

作者: 游泽渠 | 来源:发表于2016-09-16 14:52 被阅读0次

    一、环境介绍


    我目前使用的是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了。

    相关文章

      网友评论

          本文标题:linux 下的一些基本工具的使用方法

          本文链接:https://www.haomeiwen.com/subject/rlqpettx.html