天天看点

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

需要多位(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位指的都是最低位。这也是最常见的表示法,但并不是所有的微控制器都是如此。

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

图2-2 二进制数转十进制数的权值

将16位二进制数每一位的值乘以其权值,相加之后就可以将其转换成十进制数(参见图2-3)。

读者可以试着计算下列二进制数字的值:

0000

0001

0010

0011

0100

0101

……

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

图2-3 二进制转十进制示例

如果将这些二进制数看成是汽车的里程表,但是上面只有0和1两个数字。当1翻转成0时,就会进位。这就是数制中的基。

c语言中,在数字前加上0b表示二进制数。例如,给x赋值为6,用二进制表示就是:

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

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

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

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

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

对于已经超过1字节的数字(如1000),则不需要在后面加上l。

数字后面也可以加上u,以说明它是一个无符号数。

上面说的这些数字都是无符号数。8位的内存单元可以存储的数字范围是0~255。但是在c语言中也需要负数。此时,用某个位表示符号位,0表示正数,1表示负数。在计算机中,负数使用补码来表示。之所以使用补码是为了使加减法运算都可以用一种电路实现。-2的补码是:

11111110

加1后等于:

11111111

这也是-1的补码,也就是我们期望的结果:-2 + 1 = -1。如果再加1就等于:

符合我们的期望。

再回想一下前面的里程表例子,初始全是0,如果想要表示-1,就需要向后拨1,这时里程表上就全是1了。

在c语言中,用下面的方法表示有符号数:

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

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

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

图2-4 十六进制转换图

在本书中,十六进制数有时被用来描述内存中的地址,有时被用来表示数据。使用十六进制并不难,只需要多加练习即可。

一个字节可以用两位十六进制数表示。十六进制数通常排成两位或四位一组,左边是最高位。

本书中使用0x来表示十六进制数。最近也有些微芯片文献中使用“h”来表示十六进制数(但在c语言中不合法)。

图2-5给出了一些十六进制、二进制和十进制之间的换算结果。

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

图2-5 数制转换示例

显然,0xffff(某些微控制器程序存储器的地址空间的最大值)比写成1111 1111 1111 1111 或者65535要简单得多。

在c语言中,十六进制数的前面需要加上0x。例如,给x赋值26(十进制)或者1a(十六进制):

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

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

在c语言中,数字前加上0表示该数字是一个八进制数。例如,给x赋值10(十进制)或者12(八进制):

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

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

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

图2-6 dec pdp-8的前面板

上面讲到的都是整数,没有小数点。浮点数指的是有小数点且小数点可以在很大范围内移动的数字。12.34就是一个典型的浮点数,在计算机内部用1234×10-2来存储它。这两部分分别称为尾数和指数,编译器规定了这两部分的范围。在小型pic设备中,ccs c编译器使用24位尾数和6位指数,再加上尾数和指数的两个符号位,一共32位。也就是说下列数字可以表示成:

1.23 123×10-2

0.000?000?000?000?123 123×10-15

12?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语言中,浮点数有三种表示方法:

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

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

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

编程中的字符包括数字(0~9)和字母(a~z)以及标点符号和特殊符号。c语言中,每个字符都可以对应到0~255中的一个数字。而ascii码就是一套用8比特位来表示字符的标准编码。

ascii表中一共有256个字符,附录a给出了完整的ascii表。从表中可以看出,字母a在内存中是65。c语言中的字符在代码中需要用一对单引号括起来。由于c语言在类型转换时比较宽松(类型转换,同一个字符在编译器中可以有不同的解释),因此在代码中可以使用65来代替‘a’。字符赋值示例:

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

有些字符在键盘上找不到,可以用“转义”来表示它们。反斜线用来表示转义字符。如果想要使用反斜线,必须连续输入两个反斜线:\。如果要使用十六进制数表示字符,也要用到“转义”:'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赋值一个换行符。

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

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

“abcd” 在内存中的内容

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

我们使用双引号来定义字符串。上面的字符串中,一共有4个字符,但是在内存中占用5个字符(最后一个0表示字符串结尾)。因此,该字符串需要5字节的内存。

字符串中也可以包含特殊字符,例如:

"a0x42111d" 相应内存中的内容

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

上面的字符串也占用5个字节,其中字母b和c分别用十六进制和八进制表示。在c字符串中经常会用到r(回车)和n(换行)。windows文件系统在文件中使用这两个字符表示回车换行。下面的字符串表示文件中或者大多数程序终端显示的一行:

"line onern" 相应内存中的内容

还有个有意思的特性,如果代码中两个字符串之间仅存在空白字符,那么它们将被当作一个大的字符串处理。例如:

"abcd" "efgh"

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

会被当作:

"abcdefgh" 在内存中的内容

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

注意,这里丢掉了d后面的0,因为两个小字符串被当作一个大字符串处理,在内存中占9个字节。

当需要将一个很长的字符串分开写到多行中时,以及在稍后章节中将介绍的宏,都会用到这个特性。

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

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

如果表达式的结果为true,则会执行if之后的语句。如果表达式的结果为false,则不会执行if后面的语句。关系表达式a<b></b>

<b></b>

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

<b></b><b></b>

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

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

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

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

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

这个预编译指令在编译前会将所有的level替换成10。下一章中会详细介绍预编译指令。

使用const的好处在于可以指定变量类型(如上面的int)。通常,程序员使用const定义符号常量时需要将变量名全大写。

继续阅读