c语言位段的作用,C语言之文件,位运算,预处理

自从开始学习C语言不久,就听说过文件这个东西了,但就是一直都没有接触过,这次系统的一路走下来,到了这个地方,要好好了解一下。

1.所谓文件,指的是一组相关数据的有序集合,这个数据集有一个名称,叫做文件名。在前面我们已经多次使用了文件,例如源程序文件,目标文件,可执行文件,头文件等等。文件通常是驻留在外部介质上的(比如磁盘),在使用的时候才调入内存中来。操作系统是以文件为单位对数据进行管理的。

a4c26d1e5885305701be709a3d33442f.png

2.文件的分类。

<1>从用户角度来看,文件可以分为普通文件和设备文件两种。

<2>从操作系统的角度看,每一个与主机相连的输入,输出设备都看成是一个文件,比如把键盘看成输入文件,把显示器看成输出文件。

<3>按数据的组织形式,可以分为

ASCII文件(文本文件):每一个字节放一个ASCII代码

二进制文件:把内存中的数据按其在内存中的的存储形式原样输出到磁盘上存放。

3.ASCII文件和二进制文件的比较

ASCII文件便于对字符进行逐个处理,也便于输出字符,但一般占的存储空间较多,而且要花费转换的时间。二进制文件可以节省存储空间和转换时间,但是一个字节并不对应一个字符,不能直接以字符的形式输出。如果中间结果数据需要暂时保存在外存上,以后又需要输入内存的,常用二进制文件形式保存。

4.缓冲文件系统:系统自动在内存区为每一个正在使用的文件开辟一个缓冲区,用缓冲文件系统进行的输入输出又称为高级磁盘输入输出。

非缓冲文件系统:系统不会自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。用非缓冲文件系统进行的输入输出又称为低级输入输出系统。

在UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统来处理二进制文件。而ASCI

C标准只采用缓冲文件系统来处理文本文件和二进制文件。C语言对文件的读写都是用库函数来实现的。

5.文件型指针变量,这里我们使用fp指向某一个文件的结构体变量,从而通过该结构体变量中的文件信息能够访问到该文件。

a4c26d1e5885305701be709a3d33442f.png

如果有n个文件,就应该设置n个指针变量,使它们分别指向n个文件,以实现对文件的访问。下面这行代码定义了一个结构体数组f,它有5个元素,可以用来存放5个文件的信息。

6.文件的打开(fopen( )函数)

FILE

*fp;

fp =

fopen(文件名,使用文件的方式)

注意:准备访问的文件的名字,使用文件的方式,让哪一个指针变量指向被打开的文件

a4c26d1e5885305701be709a3d33442f.png

对于文件使用方式的几点说明

<1>文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:

r(read): 读

w(write): 写

a(append): 追加

t(text):

文本文件,可省略不写

b(banary): 二进制文件

+: 读和写

<2>凡是用"r"打开一个文件的时候,该文件必须已经存在,并且只能从该文件读出。

<3>用"w"打开的文件,只能向该文件写入。若打开的文件不存在,则以指定的文件名创建该文件,若打开的文件已经存在,则删除掉,重建一个新文件。

<4>若要向一个已存在的文件追加新的信息,只能用"a"方式打开该文件,但此时被打开的文件必须是存在的,否则会出错。

<5>在打开一个文件时,如果出错,fopen(

)将返回一个空指针NULL,在程序中可以用这个信息来判断是否完成打开文件的操作,并作相应的处理。

<6>把一个文本文件读入内存时,要将ASCII码转换成二进制码,而把文件以文本方式写入磁盘时,要把二进制码转换成ASCII码。

a4c26d1e5885305701be709a3d33442f.png

7.文件的关闭

函数:fclose(文件指针),功能:

使文件指针变量不指向该文件,也就是文件指针变量与文件“脱钩”,此后不能再通过该指针对原来与其相联系的文件进行读写操作。关闭成功返回0,失败返回EOF。

8.文件的读写

对文件的读和写是最常用的文件操作,C语言提供了多种文件读写函数。

a4c26d1e5885305701be709a3d33442f.png

9.fputc(

)函数,将字符(ch的值)输出到fp所指向的文件中去。

fputc(ch,fp );说明:

用写或读写的方式打开一个已经存在的文件时将清除原有文件的内容,写入字符会从文件首开始。如果需要保留文件原有的内容,让写入的字符从文件末开始存放,必须以追加的方式打开文件,被写入的文件如果不存在,则创建该文件。每写入一个字符,文件内部的位置指针向后移动一个字节。

这个函数有一个返回值,如果写入成功则返回写入的字符,失败则返回EOF,可以用这个值来判断写入是否成功。

a4c26d1e5885305701be709a3d33442f.png

10.fgetc(

)函数,从打开的文件fp中读取一个字符并送入ch中。

ch=fgetc(fp);说明:

调用fgetc()函数的时候,文件必须是以读或者读写的方式打开的。

在文件内部有一个位置指针,用来指向文件当前的读写字节。文件打开的时候,该指针总是指向文件的第一个字节,因此可以连续多次使用fgetc(

)函数,读取多个字符。

要注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,需要在程序中定义说明,只要不重新赋值,文件指针的值是不变的。文件内部的位置指针用于指示文件内部的当前读写位置,每读写一次,该指针均向后移动,它是由系统自动设置的,不需要再程序中定义说明。

a4c26d1e5885305701be709a3d33442f.png

上图中红色框中的内容实现的功能是,从一个文本文件中顺序读入字符,并在屏幕上显示出来,如果我们想从一个二进制文件中顺序读入字符并显示出来,不能直接用EOF判断文件结束,而要调用一个ANSI

C提供的函数feof( )。

a4c26d1e5885305701be709a3d33442f.png

11.让我眼前一亮的一个小操作

现在在我硬盘的某个位置有两个文件,一个图片叫做1.jpg,一个压缩文件叫做2.zip。通过下面这条命令可以生成一个3.jpg的文件,把压缩文件送进图片中。当后缀名是.jpg的时候,显示出来的就是图片,当后缀名是.zip的时候,显示的就是压缩文件。

a4c26d1e5885305701be709a3d33442f.png

copy命令的/b参数表示一个二进制文件,生成文件的大小差不多等于两个文件大小的和。原理非常简单,就是把压缩文件的二进制编码跟在图片的二进制编码后面,加载器加载的时候是按后缀来的,读取的知识标志头和结束的标志,这样我们就有了改造的可能。

12.利用文件操作,写一个自己的合成器。

a4c26d1e5885305701be709a3d33442f.png

13.fgets(

)函数,调用形式是fgets(str,n,fp);说明

从fp所指的文件中读出n-1个字符送入字符数组str中,因为在最后加一个'\0'。返回值是字符串的首地址。

a4c26d1e5885305701be709a3d33442f.png

14.fputs(

)函数,调用形式是fputs("jianbin",fp);说明

把字符串"jianbin"写入fp所指的文件。输入成功返回0,输入失败返回EOF。

a4c26d1e5885305701be709a3d33442f.png

15.数据块读写函数fread( )和fwrite( )。

a4c26d1e5885305701be709a3d33442f.png

16.格式化读写函数fprintf( )和fscanf( )

a4c26d1e5885305701be709a3d33442f.png

17.顺序读写和随机读写

顺序读写:位置指针按字节位置顺序移动。

随机读写:读写完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意位置上所需要的字符(字节),这个位置可以由我们控制。

18.fseek(

)函数,一般用于二进制文件

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.png

19.ftell(

)函数,得到流式文件中的当前位置,用相对于文件开头的位移量来表示,它返回的就是当前的位置,如果出错则返回-1L。

20.使用ferror(

)函数检测是否出错,调用形式是ferror(fp),如果返回0表示没有出错,如果返回非0值表示出错。

在调用一个输入输出函数后要立即调用ferror( )函数,否则信息会丢失。在执行fopen(

)函数的时候,ferror( )函数的初始值自动设置为0。

21.clearerr(

)函数,调用形式是clearerr(fp),它可以使文件错误标志和文件结束标志为0。只要出现错误标志,就一直保留,直到对同一文件调用clearerr(

)函数或者rewind( )函数,或任何其他一个输入输出函数。

****************************************位运算**************************************

1.位运算是按照二进制位进行的运算,因为在系统软件中,经常要处理二进制位的问题。C语言提供位运算的功能,与其他高级语言相比,具有很大的优越性,通过位运算符我们可以对数据的操作精确到每一位。

其实如果把1理解成true,把0理解成false,那么位操作和逻辑操作的规则是一样的,用这样的方式可以轻松的记住位操作的规则,没有与逻辑操作对应的一个是异或,记住相同为0,不同为1即可。

2.位运算符中除了异或,其他都是二元运算符,即要求两侧各有一个运算量。

运算量只能是整型或字符型,不能是浮点型。

a4c26d1e5885305701be709a3d33442f.png

3.&

——按位与,只要有一个为0,结果就是0。如果参加与运算的是负数,则要以补码的形式表示为二进制数,然后再进行运算。

1&1 = 1

1&0 =

0  0&1 = 0  0&0 = 0

用途:

<1>清零。若想对一个存储单元清零,即让它的全部二进制位为0,只要找到一个二进制数,满足以下条件:原来的数中为1的位,新数中都为0,然后二者进行&运算。

<2>取一个书中的某些指定位。不相干的位用0表示,用1跟要知道的位&。

4.|

——按位或,只要有一个为1,结果就是1。

1|0

= 1  1|1 = 1  0|1 = 1

0|0 =0

5.使用这个运算符完成大小写的转换。大写字母和小写字母在二进制上的区别在从右向左的第六位,第六位为0是大写字母,第六位为1是小写字母。

a4c26d1e5885305701be709a3d33442f.png

6.^表示按位异或,相同为零,不同为1。使用它可以翻转特定的位。这个运算符可以逆运算,交换两个变量的值就利用了能够逆运算的特点。

1^0 = 10^1 = 11^1 = 00^0 = 0

7.~表示按位取反

~i就是把i变量所有的二进制位取反,把0变成1,把1变成0。

8.<<

——按位左移

i=<<3表示把i的所有二进制位左移3位。左移后右边补零,如果高位在左移后溢出,就舍弃掉。左移n位相当于乘以2的n次方(在被舍弃的高位中不含1的情况下)。

9.>>————按位右移

I>>3表示把i的所有二进制位右移3位。移到右端的低位被舍弃。

右移n位相当于除以2的n次方,前提是数据不能丢失。

对于无符号数,高位补零。对于有符号数,如果原来符号位是0,则补零。如果原来符号位是1,那么有的计算机系统会补零,有的会补1,不一定。补零的称为逻辑右移,即简单右移,补1的称为算数右移。那么C语言是怎么做的?

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.png

10.位运算赋值运算符

a4c26d1e5885305701be709a3d33442f.png

11.位运算实践,取一个char a从右端开始的2-5位。

<1>先让a右移两位,目的是让要取出来的那几位移到最右端。

<2>设置一个低四位全是1,高四位全是0的数。但并不是直接0000

1111,而是用这种方式~(~0<<4),这样可以增强程序的可移植性。具体的流程是,先把0取反,全部变成1,然后左移四位,最低的四位变成0,其余都是1,然后再取反,最低的四位变成1,其余的都是0,实现了我们想要的效果。

<3>将上面两步得到的结果进行&运算。

a4c26d1e5885305701be709a3d33442f.png

12.循环移位,向右移动,把右边舍弃掉的数放到左边。

a4c26d1e5885305701be709a3d33442f.png

13.位段

信息的存储一般是以字节为单位,实际上,有时存储一个信息不必用一个或多个字节。例如布尔值真或假,用1或0来表示,使用一个位就可以了。

在计算机用于过程控制,参数检测或者数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,常常在一个字节中放几个信息。

C语言允许在一个结构体中以位为单位来指定其成员所占的内存长度,这种以位为单位的成员称为“位段”或者“位域”,利用位段能够用较少的位数存储数据。

a4c26d1e5885305701be709a3d33442f.png

说明:

<1>位段成员的类型必须指定位unsigned或者int

<2>若某一个位段要从另一个字开始存放,可以用以下形式定义

a4c26d1e5885305701be709a3d33442f.png

<3>一个位段必须存储在同一存储单元中,不能跨两个单元。如果第一个单元空间不能容纳一个位段,则该空间不用,而从下一个单元起存放该位段。

<4>可以定义无名位段

<5>位段的长度不能大于存储单元的长度,也不能定义位段数组。

<6>位段可以用整型格式输出

<7>位段可以在数值表达式中引用,它会被系统自动的转换成整型数。

14.

**************************************预处理***************************************

1.预处理功能是C语言特有的功能,它是在对源程序正式编译前,由预处理程序完成的,程序员在程序中用预处理命令来调用这些功能。使用预处理功能便于程序的修改,阅读,移植和调试,也便于实现模块化程序设计。

2.无参宏定义。无参宏的宏名前不带参数,其定义的一般形式如下图,注意它就是用后面的替换前面的,最后不需要分号,加了分号会出错!

a4c26d1e5885305701be709a3d33442f.png

#表示这是一条预处理命令,凡是以#开头的都是预处理命令。define为宏定义命令。

标识符为所定义的宏名,字符串可以是常数,表达式等。

3.说明

<1>在对源程序编译时,将会先由预处理程序进行宏替换,然后再进行编译。预处理程序不会对宏进行任何检查,如果有错误,只能在编译已被宏展开后的源程序中发现。

<2>宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可以使用#undef命令。

<3>在源程序中,宏名如果用引号括起来,则预处理程序不对其进行替换,因为双引号括起来是当做常量字符串看待的。

<4>宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层替换。

<5>习惯上宏名用大写字母表示,以便于和变量区分,但是也允许用小写字母。

4.宏定义和typedef的区别

宏定义只是简单的字符串替换,是在预处理的时候完成的,而typedef是一个语句,后面有分号,它是在编译的时候被处理的。typedef不是简单的替换,而是对类型说明符重新命名,被命名的标识符具有类型说明定义的功能。

a4c26d1e5885305701be709a3d33442f.png

还可以对“输出格式”进行宏替换,减少书写的麻烦,不过这个肯定不常用,可移植性太差。

a4c26d1e5885305701be709a3d33442f.png

5.带参宏定义

C语言允许宏带有参数,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。其实更好的方式是把参数叫参数,把实际传入的参数叫值。

对带参数的宏,在调用时,不仅宏要展开,而且要用实参去代替形参。

带参宏定义的一般形式为

#define

宏名(形参表)  字符串

带参宏调用的一般形式为

 宏名(实参表)a4c26d1e5885305701be709a3d33442f.png

6.说明:

<1>在带参宏定义中,宏名和形参表之间不能有空格出现。

<2>在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值,要用它们去替换形参,所以必须作类型说明。这与函数中的情况是不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参赋给形参,进行“值传递”,而在带参宏中,只是符号代替,不存在值传递的问题。

<3>在宏定义中的形参是标识符,而宏调用中的形参可以是表达式。

<4>在宏定义中,字符串内的形参通常要用括号括起来以避免出错。

a4c26d1e5885305701be709a3d33442f.png

<5>带参宏和带参函数很相似,但有本质上的不同,除了上面已经谈到的各点外,把同一个表达式用函数处理与用宏处理,两者得到的结果可能是不一样的。

<6>宏定义也可以用来定义多个语句,在宏调用时,把这些语句又代换到源程序中,

7.对文件包含命令的说明

<1>一个include命令只能指定一个被包含文件,若有多个文件需要包含,则需要用多个include命令,不能用一条命令,中间逗号分隔。

<2>文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。比如这个页面包含了a.h,又可以在a.h中包含b.h。

<3>包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来,

但是这两种形式是有区别的:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置目录的时候设置的),而不在源文件目录中去查找。

而使用双引号则表示首先在当前的源文件目录中查找,

若未找到才到包含目录中查找,我们编程时可根据自己文件所在的目录来选择某一种命令形式。

8.条件编译

预处理程序提供了条件编译功能,可以按照不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,条件编译有三种规则。

<1>这种形式的功能是,如果标识符已经被#define命令定义过,则对程序段1进行编译,否则对程序段2进行编译。如果不需要程序段2,可以写成右图所示的形式。

a4c26d1e5885305701be709a3d33442f.pnga4c26d1e5885305701be709a3d33442f.png

<2>这种形式是,如果标识符没有被#define命令定义过,则对程序段1进行编译,否则对程序段2进行编译。

a4c26d1e5885305701be709a3d33442f.png

<3>如果常量表达式为0,则可以实现注释的效果。

a4c26d1e5885305701be709a3d33442f.png

9.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值