makefile以及通用的makefile脚本、C语言文件操作以及加密相关,开源项目学习方法,main的参数

C/C++代码编程可执行程序的过程:

            1、预处理
    
            2、编译
    
            3、汇编 
    
            4、链接 

什么是makefile脚本: 

    Makefile脚本集合了程序的编译指令的文件,make是一个命令工具,当执行make命令时,它会自动读取MakeFile中的编译指令并执行,会自动完成整个项目的自动化编译工作。
    
    为什么需要Makefile脚本:
        项目中如果有很多.c文件,他们的编译指令会有很多,需要的编译时间比较长,依赖关系非常复杂。
        当项目中的.h文件被修改时,.c文件,我们无法人为分辨出哪些文件需要重新编译,只能全部重新编译一下,但这项操作非常耗时。
        所以使用makefile脚本编译项目:(按重要性排序)
            1、节约时间
            2、记录文件之间的依赖关系
            3、自动化执行编译过程
             

Makefile脚本的原理: 

    Makefile脚本的原理就是基于文件的最后修改时间,被依赖文件的最后修改时间晚于目标文件,该文件就需要重新编译。
        如果hello.c > hello.c 那么gcc -c hello.c
            hello.h > hello.o             gcc - c hello.c 

Makefile脚本的格式: 

    由若干个编译目标组成,它类似C语言中的函数,就是若干个编译指令组成的编译模块,默认只执行排在第一个的编译目标,也叫入口目标。
        
    target ...: prerequisites ...
        command
        ...
        ...
    
    target:编译目标,它如果不存在,或者早于它依赖的文件,那么就执行该下面的编译指令。
    prerequisites:被依赖的编译目标、文件,相当于c语言的函数调用。
    command: 编译指令 

在makefile脚本中可以使用变量: 

    变量名=value 定义变量并给变量赋初值
    
    $(变量名) 使用变量名,获取出变量的值。
    常用变量名:
        CC=编译器
        STD=语法标准
        FLAG=检查标准, -wall、 -werror
        TARGE=最终可执行文件名字
        OBJECT=所有的目标文件名 

负责清理的编译目标: 

    该编译目标一般负责删除目标文件、头文件的编译结果、可执行文件。
    一般它不会被依赖,也就是不会执行,而是当需要时,在命令行通过make 目标名,手动执行。
    什么时候需要它执行:
        1、刚修改的内容,并没有发生变化,有可能是依赖规则有问题,代码并没有重新编译,那么执行它就可以删除所有目标文件,可执行文件,重新编译
        2、更换了执行平台后,那么之前编译出的目标文件就全部不能再继续使用。
        3、项目最终上线时,会把所有的编译结果删除,重新编译。

    clean:
        rm -rf $(BOJECT) $(TARGE)
        rm -rf .h.gch


        


     Makefile 里有什么? Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。 

通用的MakeFile脚本 

此处是以 main,tools,manager_user 这三个文件举例

CC=gcc                                
STD=-std=gnu99                  

FLAG=-Wall -Werror
TARGE=manager
OBJECT=main.o tools.o manager_user.o

$(TARGE):$(OBJECT)
    $(CC) $(OBJECT) -o $(TARGE) 

main.o:%.o:%.c manager_user.h
    $(CC) $(STD) $(FLAG) -c $<

tools.o:%.o:%.c tools.c tools.h
    $(CC) $(STD) $(FLAG) -c $<

manager_user.o:%.o:%.c manager_user.c manager_user.h tools.h
    $(CC) $(STD) $(FLAG) -c $<

 常见的问题: 

    1、使用makefile的好处
        节约编译时间
        记录文件的依赖关系
        自动执行编译过程
    2、Makefile的原理
        1、在命令行执行make命令(make是安装在操作系统上的读取、解析、执行makefile的工具)
        2、make命令会读取当前目录下的makefile、makefile文件中的内容,解析里面的编译目标。
        3、根据依赖关系和文件的最后修改时间,来判断是否需要执行编译命令以达到节约时间的目的。
    3、makefile脚本中有哪些内容
        变量
        入口目标
        被依赖的目标
        伪目标
        注释
        可执行编译指令
        系统命令 

文件分类: 

    int num = 2048;
    二进制文件:把数据的=补码直接写入文件,这种文件叫二进制文件
    优点:     1、读写和写入时不需要进行转换,所以读写速度快
            2、数据安全性高
    缺点:     1、不能使用文本编辑器打开,无法阅读
     0000 0000 0000 0000 0000 1000 0000 0000
    文本文件:把数据转换成字符串写入文件,这种文件叫文本文件,
    优点:1、能够被文本编辑器打开,人类能看得懂,能看出数据是否出错。
    缺点:1、读写时需要转换,读写速度慢,数据有被修改的风险。
    “2048”
    2’‘0’‘4’‘8’
    50     48    52    56
    00110010 00110000 00110100 00111000


    总结:二进制文件的大小时确定的,文本文件会根据数据的内容而变化,大小不确定 

打开关闭文件: 

    

FILE *foen(const char *path,const char *mode);


    功能:打开文件
    path:文件的路径
    mode:文件的打开模式
    返回值:文件结构指针,是后续操作文件的凭证,失败的话会返回NULL
    
    文件的打开模式:
        “r”以只读方式打开文本文件,如果文件不存在,或文件没有读权限则打开失败
        “w”以只写方式打开文本时,如果文件不存在,则创建,如果文件存在则清空文件的内容,如果文件存在且没有写权限,则打开失败
        “a”以只写方式打开文本时,如果不存在则创建,如果文件存在则新写入的内容追加到文件末尾,如果文件存在且没有写权限,则打开失败
        
        “r+”以读、写方式打开文本文件,如果文件不存在,或文件没有读写权限则打开失败。
        “w+”以读、写方式打开文本文件,如果文件不存在,则创建,如果文件存在则清空文件的内容,如果文件存在且没有读、写权限,则打开失败
        “a+”以读、写方式打开文本时,如果不存在则创建,如果文件存在则新写入的内容追加到文件末尾,如果文件存在且没有读、写权限,则打开失败
        
        以文本方式打开文件时,如果要写入的字符是'\n'时,系统会写'\n'和'\r',两个字符,在windows系统中以'\n'+'\r'表示一个换行,在读取数据时,遇到'\n''\r'只会读取一个'\n'。
        也就是当写入数字0x0a时,会写入0x0a0d,在Linux、Unix系统下则只会写入'\n'一个字符
        ,操作是不需要加b


        注意:如果要操作二进制文件,则在以上模式的基础上增加b,eg:“rb+”


        
    

int fclose(FILE *stream);


    功能:关闭文件
    返回值:成功返回0,失败返回-1


    注意:不能重复关闭,否则会出现double free的错误,为了防止出现野指针,文件关闭后最后把文件指针赋值为NULL,及时关闭文件可以把缓冲区中的数据写入到文件中。 

 文本文件的读写:

  

 int fprintf(FILE *stream, const char *format, ...);


    功能:把若干个变量以文本格式写入到指定文件中
    stream:要写入的文件
    format:占位符+转义字符+
    ...:若干个变量
    返回值:写入字符的数量
    
    下面两个函数的功能fprintf也能实现


    

int fputc(int c, FILE *stream);


    功能:写入一个字符到文件中
    

int fputs(const char *s, FILE *stream);


    功能,写入一个字符串到文件中
    
  

  int fscanf(FILE *stream, const char *format, ...);


    功能:从文件中读取数据
    stream:要读取的文件
    format:占位符
    ...:若干个变量的地址
    返回值:成功读取的变量个数
    

    char *fgets(char *s, int size, FILE *stream);
    int getc(FILE *stream); 

二进制文件的读写: 

    注意:以二进制格式读写文件时,最好加上mode最好包含b
    

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);


    功能:把一块内存当做数组,然后数组中的内容写入到文件中
    ptr:写入的内容首地址(数组首地址)
    size:一次写入的数字数(数组元素的字节数)
    nmemb:写入的次数(数组的长度)
    stream:要写入的文件
    返回值:实际写入的次数

    

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);


    功能:把二进制文件中的内容读取的数组中
    ptr:要存储数据的数组首地址
    size:数组元素的字节数
    nmemb:数组的容量
    返回值:成功读取的次数
    


    注意:如果以fwrite/fread读写的字符串,那么我们操作的依然是文本文件

文件位置指针: 

     文件位置指针它记录着读写文件时的位置,读取数据时从文件位置指针处读取,写入数据时也会写入到文件位置指针所指向的位置,并且它会随着读写操作自动移动。
    以“r”、“r+”方式打开文件,文件位置指针指向文件的开头。
    以“a”、“a+”方式打开文件,文件位置指针指向文件的末尾。
    
    

 int  fseek(FILE  *stream,  long   offset,   int whence);


    功能:设置文件的位置指针
    stream:要设置的文件
    offset:偏移值
    whence:基础位置
        SEEK_SET    文件开头
        SEEK_CU    当前位置
        SEEK_END    文件末尾
    whence + offset 就是文件指针最终设置的位置
    返回值:成功返回0,失败返回1
    
  

 long ftell(FILE *stream);


    功能:返回文件位置指针指向第几个字节
    
  

 void rewind(FILE *stream);


    功能:把文件位置指针调整到文件开头。

文件操作时的局限性: 

    文件的内容是连续存储在硬磁盘上的,所以就导致以下操作:
        向文件中插入数据:
            1、文件位置指针调整到要插入的位置。
            2、把后续的数据整体向后拷贝n个字节(要插入的数据字节数)
            3、文件位置指针调整到要插入的位置,写入数据
        从文件中删除数据:
            1、文件位置指针调整到要删除的数据末尾;
            2、把后续的数据整体向前拷贝n个字节(要删除的数据字节数)
            3、修改文件的大小。
    所以,程序在运行时,先把数据从文件中加载到内存中,程序在运行期间只针对内存进行增删改查,程序结束时再把数据从内存写入到文件 

文件管理: 

    

int remove(const char *pathname);


    功能:删除文件
    
  

 int rename(const char *oldpath, const char *newpath);


    功能:重命名文件
    
  

 int truncate(const char *path, off_t length);


    功能:把文件的内容设置成length字节数
    
  

 char *tmpnam(char *s);


    功能:生成一个与当前文件系统不重名的文件名。(整个磁盘的范围)
    
    

int access(const char *pathname, int mode);


    功能:检查文件的权限
    R_OK 读权限
    W_OK 写权限
    X_OK 执行权限
    F_OK 文件是否存在
    返回值:
        检查的权限如果存在则返回0,不存在则返回-1。 

结构体序列化: 

    把结构体变量转换成字符串的过程中序列化,反序列化就是把字符串转换成结构变量的过程。
    为什么把结构变量转换成字符串:
        1、网络通信时传输的是大端序列,而个人计算机使用的是小端序列,为了避免传输时各成员的大小端转换,所以把结构转换成字符串传递更方便。
        2、在使用SQL语言操作数据库时,SQL是以字符串形式操作数据库的。
    方法一:使用sprintf/scanf对简单的结构变量进行序列化和反序列化。
        sprintf(arr,“提示信息+占位符”,若干个结构.成员变量);
        sscanf(str,“提示信息+占位符”,&若干个结构.成员变量);
        
    方法二:把结构变量转换成json格式的字符串,了解cjson库的使用
 

经典开源项目的学习步骤: 

    1、阅读README文件
        版权信息介绍
        使用方法介绍
        编译方法介绍
        原理、示例、局限性
        依赖的工具、库
        使用时的注意事项
    
    2、编译项目,执行测试程序,阅读测试代码
    3、查看示例代码,学习如何使用
    4、查看源码,进行学习,上网寻找一些对源解析的文章、博客
    5、重新造个轮子 

main函数参数: 

     完整的main函数格式:
    

int main(int argc,const char* argv[ ])


    
    我们在命令行执行程序时,可以附加一些参数,这些参数会以字符串形式传递给main函数
    argc:代表字符串个数,也就是指针数组的长度
    argv:指针数组,里面存储着每个字符串的首地址。
    

    for(int i=0; i<argc; i++)
    {
        
    }


    
    ./a.out 执行程序时,argc的值是1

 数据加密:

    对称加密:
        明文 经过处理 得到密文
        密文 经过解密 得到明文
        最简单的对称加密:
            A ^ B = C
            C ^ B = A
            A ^ C = B
        
    非对称加密:
        数据经过加密处理能得到独一无二的密文,而密文无法还原出明文,这种算法一般用于用户登录、验证文件的完整性
        md5算法是一种非对称加密 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值