C语言多文件编译与文件操作(linux)

一、多文件编程

1、多文件编程步骤

①把所有函数分解在不同的源文件里,主函数要是单独的文件

②为每个源文件编写以.h作为拓展名的头文件,主函数不需要头文件,只要是不分配内存的内容都可以写在头文件里,至少要包含配对源文件所有函数的声明语句

③在所有源文件里使用#include指令包含必要的头文件,配对头文件都是必要的头文件

④为了防止多个函数包含同样的头文件造成重复编译,需要为头文件加上头文件卫士(#ifndef.....#define.....#endif),意思是如果定义了该宏,就不在重复定义,保证了头文件只被编译一次,也就是条件编译

例如:

//此为add.c文件
#include"add.h"
int add(int val,int val1){
    return val+val1;
}



//此为add.h文件
#ifndef _ADD_H
#define _ADD_H
#include<stdio.h>
int add(int,int);//函数声明
#endif



//此为main.c文件
#include"add.h"
int main(void){
    printf("%d\n",add(5,8));
    return 0;
}

2、gcc的编译过程(从.c源码到可执行文件)

用图来说明一下,基本通过这几步得到一个可执行文件

  gcc的其他选项
    -o ,认为给定输出的可执行文件名,如果不给出这个选项,gcc就给出预设的可执行文件a.out。
    -g,产生符号调试工具(GNU的gdb),要想对源代码进行调试,我们就必须加入这个选项。 
    -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化               处理,这样产生的可执行文件的执行效率可以提高,    但是,编译、连接的速度就相应地               要慢一些。


    -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。

    -D ,可以在后面定义宏名

3、条件编译

从几组语句中选择一组进行编译

#ifdef.....#else.....#endif  //如果定义了宏,则编译ifdef下语句,否则执行else下语句

#ifndef.....#else......#endif  //与上述效果相反

#if.........#elif(任意多次)......#else........#endif //可以根据宏的定义从多组语句中选择一组编译,#if                                                                          //和#elif后写逻辑表达式,可以包括任意逻辑操作符

例如:

#include<stdio.h>
int main(void){
#ifdef HP
    printf("ok\n");
#else
    printf("error\n");
#endif
    return 0;
}
//直接运行时结果会打印error
//如果编译时 gcc -D HP去定义这个宏,运行结果会打印ok
//如果把#ifdef换成#ifndef,那么结果会反过来
#include<stdio.h>
int main(void){
#if defined(HP)//如果定义了布尔值会为1
    printf("1\n");
#elif !defined(WJ)
    printf("2\n");
#else
    printf("3\n");
#endif
    return 0;
}
//定义了哪个宏就会输出哪个

4、Makefile的使用

1.Make是自动编译管理器,这里的“自动”是指它能构根据文件时间戳自动发现更新过的文件而减少
    编译的工作量,同时,它通过读入Makefile来执行大量的编译工作
 2.make工具的作用
    当项目中包含多个c文件,但只对其中1个文件进行了修改,gcc编译会将所有的文件从头编译一      遍,这样效率会非常低,所以通过make工具,只对修改过的文件进行编译,这样大大减少了编      译时间,提高编译效率  
 3.Makefile是Make读入的唯一配置文件 
 4.Makefile的编写格式
   格式:
       目标:依赖
       <tab> 命令(注意一定是<TAB>键,不要用空格)
      目标实现,需要通过依赖文件实现

  例如编写一个基本的Makefile(名称不能变)文件,写出依赖关系,以及如何得到这些目标文件      的命令,  .PHONY:clean 声明一个伪命令。若之前的目标中有生成可执行文件名为clean。执行      “make clean”时,make会认为clean目标已实现。不执行clean目标对应的指令,用.PHONY声明    后,make认为clean是一个指令,“make clean”时会执行clean指令对应的命令,这里删除所有的    生成的.o文件和a.out文件。

a.out:add.o main.o
    gcc add.o main.o -o add
add.o:add.c
    gcc -c add.c -o add.o
main.o:main.c
    gcc -c main.c -o main.o
.PHONY:clean
clean:
    rm *.o a.out


 通过变量来改写Makefile的方法,比传统方法相对来说较为简单,更容易维护 
     1)预定义变量
        CC 默认值为cc,与gcc同
        RM 默认值为rm -f 
        CFLAGS 无默认值,一般为c编译器的选项
        OBJS 一般为目标文件xx.

    2)自动变量:
        $<    第一个依赖文件的名称
        $@  目标文件的完整名称
        $^    所有不重复的目标依赖文件,
            以空格分开 %  匹配所有

例如:

我们有如下这些文件需要,stu_sytem.c为主函数,

 

5、文件操作

标准IO:input/output,针对于文件输入输出。

linux下文件类型:

b(块设备) c(字符设备) d(目录) -(普通文件) l(链接文件) s(套接字) p(管道)

概念:在C库中定义的一组专门用于输入输出的函数

  1. 标准IO通过缓冲机制减少系统调用的次数,提高效率

  2. 标准IO围绕流进行操作,流用FILE *描述;(FILE 就是一个结构体,用于存放操作文件的相关信息,它在stdio.h文件中定义;vi -t FILE,ctags,ctrl+]:代码追踪,ctrl+t:回退

  3. 标准IO默认打开了三个流,stdin(标准输入)、stdout(标准输出)、stderr(标准出错)(FILE *stdin)

文件里的内容都是采用二进制的方式来记录,所有的二进制数字都来自于字符,叫做文本文件,其他文件叫做二进制文件,文本文件也可以看成二进制文件。

两种操作文件的方法:①只操作文本文件   ②操作所有文件

基本步骤:

1、打开文件(fopen)

2、操作文件(fgetc、fputc、fread、fwrite)

3、关闭文件(fclose)

FILE*fopen(const char *path.const char*mode)

功能:打开文件

参数:

path:文件路径

mode:打开方式

"r":只看不改,从文件头开始看

"r+":增加了修改文件的功能

"w":只改不看,从文件头开始修改,文件不存在就创建文件,文件存在删除文件内所有内容

"w+":比w多了查看文件的内容功能

"a":只改不看,从原有内容末尾追加新内容

"a+":比a多了查看文件内容的功能

"b":采用二进制操作文件

返回值:

成功:返回一个FILE*类型的文件指针,保存打开文件的入口地址

失败:返回NULL

int*fclose(FILE*stream)

功能:关闭一个文件

参数:

stream:fopen返回的地址

返回值:

成功:返回0

失败:返回EOF,errno(错误码)被设置

int fgetc(FILE * stream)

功能:从文件中读取一个字符

参数:stream:文件流

返回值:成功:读到的字符

失败或读到文件末尾:EOF(-1)

int fputc(int c, FILE * stream)

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

参数:c:要写的字符ASCII,输入字符也会被隐式转换,因此可以直接输入字符

stream:文件流

返回值:成功:写的字符的ASCII

失败:EOF

int feof(FILE * stream);

功能:判断文件有没有到结尾

返回:到达文件末尾,返回非零值

int ferror(FILE * stream);

功能:检测文件有没有出错

返回:文件出错,返回非零值

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

功能:从文件中每次读取一行字符串

参数:s:存放字符串的地址

size:一次读取的字符个数

stream:文件流

返回值:成功:s的地址

失败或读到文件末尾:NULL

特性:每次实际读取的字符个数为size-1个,会在末尾自动添加\0

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

功能:向文件中写字符串

参数:s:要写的内容

stream:文件流

返回值:成功:非负整数

失败:EOF

代码理解:

fread(读操作)、fwrite(写操作)---》二进制方式

都需要四个参数

① 第一个存储区地址

②单个存储区大小

③希望操作的存储区个数

④文件指针

返回值:代表实际操作的存储区个数

 以文本方式操作文件

fprintf函数:把数字记录到文本文件里,参数比printf()函数多一个,第一个参数是文件指针

fscanf函数:可以从文本文件中获得数字并记录到存储区,参数比scanf(函数多一个),第一个参数是文件指针

两种方式操作的文件内容不同:

 

计算机会为每个打开的文件保留一个整数,以记录下次读写的位置,此整数表示文件头到这个位置包含的字节个数叫做文件位置指针

ftell 获得位置指针数值

rewind 将位置指针移到文件开头

fseek 将位置指针移动到任何位置

参数:

stream:文件指针

offset:偏移量

whence:基准

SEEK_SET 把文件头作为基准

SEEK_CUR 把当前位置作为基准

SEEK_END 把文件尾作为基准,尾部应该是实际尾部字符再往后移两位

 注:一般操作的是字符串类型

freopen函数,比fopen函数最后多了一个流参数,使用如下

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值