《嵌入式C编程:PIC单片机和C编程技术与应用》一2.2 C常量语法

    xiaoxiao2024-03-30  9

    本节书摘来自华章出版社《嵌入式C编程:PIC单片机和C编程技术与应用》一书中的第2章,第2.2节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问云栖社区“华章计算机”公众号查看

    2.2 C常量语法

    2.2.1 二进制

    需要多位(bit)二进制数才能表示一个大于1的值,具体需要多少位,则取决于数字大小。一个8位的二进制数(一个字节)可以表示256个数字(0~255)。16位的二进制数可以表示从0到65?535的值。如果使用一个字节来传输信息,一共可以传输256种可能的组合,足以表示十进制数、大小写字母,以及其他一些符号。一般情况下,使用ASCII(美国信息交换标准码)编码规范来表示这些字符。二进制数第0位的权值是2的0次方,第1位的权值是2的1次方,第2位的权值是2的2次方,以此类推。如果第0位是1,那么它的值是1×20 = 1;如果是0,它的值则是0×20 = 0。如果第1位是1,那么它的值是1×21=2;如果是0,它的值则是0×21 = 0。如果第3位是1,那么它的值是1×23=8;如果是0,它的值则是0×23 = 0。对于16位的二进制数来说,第0位是最低位(least significant bit),第15位是最高位(most significant bit)。图2-2给出了每一位的权值(也就是说如果该位为1,其他位为0)所代表的十进制数。在所有PIC相关的文档中,第0位指的都是最低位。这也是最常见的表示法,但并不是所有的微控制器都是如此。

    图2-2 二进制数转十进制数的权值 将16位二进制数每一位的值乘以其权值,相加之后就可以将其转换成十进制数(参见图2-3)。 读者可以试着计算下列二进制数字的值: 0000 0001 0010 0011 0100 0101 ……

    图2-3 二进制转十进制示例 如果将这些二进制数看成是汽车的里程表,但是上面只有0和1两个数字。当1翻转成0时,就会进位。这就是数制中的基。 C语言中,在数字前加上0b表示二进制数。例如,给x赋值为6,用二进制表示就是:

    2.2.2 十进制

    十进制就是我们经常使用的计数方式。每个数位可以使用0~9这十个符号表示不同的数值。C语言中我们这样使用它:

    稍后再来介绍“类型”。这里我们注意到,编译器将会把123当作1字节来处理,因为一个字节足以存储123。如果由于某种原因,程序员需要编译器将其当作两个字节,那么可以在数字后加上L(long):

    对于已经超过1字节的数字(如1000),则不需要在后面加上L。 数字后面也可以加上U,以说明它是一个无符号数。

    2.2.3 有符号整数

    上面说的这些数字都是无符号数。8位的内存单元可以存储的数字范围是0~255。但是在C语言中也需要负数。此时,用某个位表示符号位,0表示正数,1表示负数。在计算机中,负数使用补码来表示。之所以使用补码是为了使加减法运算都可以用一种电路实现。-2的补码是:11111110加1后等于:11111111这也是-1的补码,也就是我们期望的结果:-2 + 1 = -1。如果再加1就等于:00000000符合我们的期望。再回想一下前面的里程表例子,初始全是0,如果想要表示-1,就需要向后拨1,这时里程表上就全是1了。在C语言中,用下面的方法表示有符号数:

    2.2.4 十六进制

    十六进制使用16个符号计数:0~9以及A~F。这次可以设想下我们的里程表上每位有16种符号。使用十六进制数可以很好地帮助程序员理解每一位的值;如果使用二进制,就会显得很长,不方便记忆和交流。不像平常(在现实世界中)使用的十进制那样,十六进制和二进制之间可以直接换算。每个十六进制位占用4个比特位。十六进制的每个数字都可以用一个4比特的二进制数表示(见图2-4)。许多程序员都能记住每个十六进制数字对应的二进制数,这样他们就可以直观地看到十六进制数对应的二进制形式了。例如,期望传送过来的数字是AA(0b1010 1010),但是得到的却是55(0b0101 0101),我们立即就知道数据在传输中错乱了一位。

    图2-4 十六进制转换图 在本书中,十六进制数有时被用来描述内存中的地址,有时被用来表示数据。使用十六进制并不难,只需要多加练习即可。 一个字节可以用两位十六进制数表示。十六进制数通常排成两位或四位一组,左边是最高位。 本书中使用0x来表示十六进制数。最近也有些微芯片文献中使用“h”来表示十六进制数(但在C语言中不合法)。 图2-5给出了一些十六进制、二进制和十进制之间的换算结果。

    图2-5 数制转换示例 显然,0xFFFF(某些微控制器程序存储器的地址空间的最大值)比写成1111 1111 1111 1111 或者65535要简单得多。 在C语言中,十六进制数的前面需要加上0x。例如,给x赋值26(十进制)或者1A(十六进制):

    2.2.5 八进制

    八进制的基是8个分别代表不同数值的数字(0~7)。和十六进制一样,八进制也可以直接换算成二进制。每个八进制位占3个比特位。在十六进制流行之前,早期的计算机使用的是八进制,因为可以直接使用开关输入指令(见图2-6)。虽然已经很少有人再用八进制了,但是C语言仍就将其纳入自己的语法中。在C语言中,数字前加上0表示该数字是一个八进制数。例如,给x赋值10(十进制)或者12(八进制):

    注意,等号后面的是数字0而不是字母O。即使你不打算用八进制,这里也要特别注意,在十进制的数字前加上0就变成了八进制。上面那行代码中,x是10,而不是12。

    图2-6 DEC PDP-8的前面板 注: DEC PDP的控制杆用来输入二进制机器指令,然后使用load按钮将指令加载到内存中。注意,每3个控制杆为一组,被分成不同颜色。每组对应一个八进制数。这种计算机在C语言出现之前就已经非常流行。(PDP-8的图片由Herb Johnson提供, http://www.retrotechnology.com)

    2.2.6 浮点数

    上面讲到的都是整数,没有小数点。浮点数指的是有小数点且小数点可以在很大范围内移动的数字。12.34就是一个典型的浮点数,在计算机内部用1234×10-2来存储它。这两部分分别称为尾数和指数,编译器规定了这两部分的范围。在小型PIC设备中,CCS C编译器使用24位尾数和6位指数,再加上尾数和指数的两个符号位,一共32位。也就是说下列数字可以表示成:1.23 123×10-20.000?000?000?000?123 123×10-1512?300?000?000?000?000 123×1014但是数字:1?200?000?000?000?003 1?200?000?000?000?003×100只能转换成:1?200?000?000?000?000 120×1014因为尾数部分没有那么长来容纳这么多有效位。由于浮点数在计算机中其实是一种不精确的表示,存在舍入误差,因此在比较两个浮点数时,不能使用小于和大于,而只能用等于和不等于。在C语言中,浮点数有三种表示方法:

    2.2.7 定点数

    定点数的小数点是固定的。在计算机中不需要存储小数点的位置,不需要区分尾数和指数,只需要像整数一样存储,编译器和处理器会使用约定的小数点位置来处理定点数。这种计算机结构简单,造价低廉。在程序中这样表示:

    2.2.8 字符

    编程中的字符包括数字(0~9)和字母(A~Z)以及标点符号和特殊符号。C语言中,每个字符都可以对应到0~255中的一个数字。而ASCII码就是一套用8比特位来表示字符的标准编码。ASCII表中一共有256个字符,附录A给出了完整的ASCII表。从表中可以看出,字母A在内存中是65。C语言中的字符在代码中需要用一对单引号括起来。由于C语言在类型转换时比较宽松(类型转换,同一个字符在编译器中可以有不同的解释),因此在代码中可以使用65来代替‘A’。字符赋值示例:

    有些字符在键盘上找不到,可以用“转义”来表示它们。反斜线用来表示转义字符。如果想要使用反斜线,必须连续输入两个反斜线:\。如果要使用十六进制数表示字符,也要用到“转义”:'x41'(也就是字母'A'),用八进制表示就是'101'。表2-1列出了一些特殊字符。 表2-1 C语言转义字符 n 换行——x0a v 垂直制表——x0b r 返回——x0d ? 问号——x3f t 制表——x09 ’ 单引号——x22 b 退格——x08 ” 双引号——x22 f 换页——x0c \ 反斜杠——x5c a 响铃——x07

    注意,在使用反斜线时前面必须再加上一个反斜线表示这是个转义字符,有时还需要使用单引号或双引号。例如,下面这几行代码的功能是一样的,都是给变量c赋值一个换行符。

    2.2.9 字符串

    将一组字符连续存储在内存中,并以空字符'000'结尾,就构成了C语言中的字符串。例如:“ABCD” 在内存中的内容

    我们使用双引号来定义字符串。上面的字符串中,一共有4个字符,但是在内存中占用5个字符(最后一个0表示字符串结尾)。因此,该字符串需要5字节的内存。字符串中也可以包含特殊字符,例如:"A0x42111D" 相应内存中的内容

    上面的字符串也占用5个字节,其中字母B和C分别用十六进制和八进制表示。在C字符串中经常会用到r(回车)和n(换行)。Windows文件系统在文件中使用这两个字符表示回车换行。下面的字符串表示文件中或者大多数程序终端显示的一行:"Line Onern" 相应内存中的内容 还有个有意思的特性,如果代码中两个字符串之间仅存在空白字符,那么它们将被当作一个大的字符串处理。例如:"ABCD" "EFGH"

    会被当作:"ABCDEFGH" 在内存中的内容

    注意,这里丢掉了D后面的0,因为两个小字符串被当作一个大字符串处理,在内存中占9个字节。当需要将一个很长的字符串分开写到多行中时,以及在稍后章节中将介绍的宏,都会用到这个特性。

    2.2.10 真和假

    每个C语言表达式都可以得出一个数值。使用关系运算符的表达式的值可能是TRUE(1,真)或FALSE(0,假)。关系表达式通常用在if或while语句中:

    如果表达式的结果为TRUE,则会执行if之后的语句。如果表达式的结果为FALSE,则不会执行if后面的语句。关系表达式a

    2.2.11 常量

    前面已经用过这种简单的数据声明:

    还可以在它前面加上关键字const来声明一个符号常量:

    定义好符号常量之后,在程序中可以直接使用常量名来代替该常量。还有一种更常用的定义常量的方法:

    这个预编译指令在编译前会将所有的LEVEL替换成10。下一章中会详细介绍预编译指令。使用const的好处在于可以指定变量类型(如上面的int)。通常,程序员使用const定义符号常量时需要将变量名全大写。 相关资源:嵌入式C编程 PIC单片机和C编程技术与应用
    最新回复(0)