2.3 常量
类似于 1234
的整数常量属于 int
类型,long
类型的常量以字母 l
或 L
结尾,如 123456789L
如果一个整数太大以至于无法用 int
类型表示时,也将被当作 long
类型处理
无符号常量以字母 u
或 U
结尾
后缀 ul
或 UL
表明是 unsigned long
类型
浮点数常量中包含一个小数点(如 123.4
)或一个指数(如 1e-2
),也可以两者都有
没有后缀的浮点数常量为 double
类型,后缀 f
或 F
表示 float
类型,而后缀 l
或 L
则表示 long double
类型
整型数除了用十进制表示外,还可以用八进制或十六进制表示
带前缀 0
的整型常量表示它为八进制形式;前缀为 0x
或 0X
,则表示它为十六进制形式
例如,十进制数 31
可以写成八进制形式 037
,也可以写成十六进制形式 0x1f
或 0X1F
八进制与十六进制的常量也可以使用后缀 L
表示 long
类型,使用后缀 U
表示 unsigned
类型
例如,0XFUL
是一个 unsigned long
类型(无符号长整型)的常量,其值等于十进制数 15
一个字符常量是一个整数,书写时将一个字符括在单引号中,如 'x'
字符在机器字符集中的数值就是字符常量的值
例如,在 ASCII 字符集中,字符 '0'
的值为 48
,它与数值 0
没有关系
如果用字符 '0'
代替这个与具体字符集有关的值(比如 48
),那么,程序就无需关心该字符对应的具体值,增加了程序的易读性
字符常量一般用来与其它字符进行比较,但也可以像其它整数一样参与数值运算
某些字符可以通过转义字符序列(例如,换行符 \n
)表示为字符和字符串常量
转义字符序列看起来像两个字符,但只表示一个字符
另外,可以用 '\ooo'
表示任意的字节大小的位模式
其中,ooo
代表 1 ~ 3 个八进制数字(0…7)
这种位模式还可以用 '\xhh'
表示,其中,hh
是一个或多个十六进制数字(0…9,a…f,A…F)
因此,我们可以按照下列形式书写语句:
#define VTAB '\013' /* ASCII vertical tab */
#define BELL '\007' /* ASCII bell character */
上述语句也可以用十六进制的形式书写为:
#define VTAB '\xb' /* ASCII vertical tab */
#define BELL '\x7' /* ASCII bell character */
ANSI C 语言中的全部转义字符序列如下所示:
\a
响铃符、\\
反斜杠、\b
回退符、\?
问号、\f
换页符、
\'
单引号、\n
换行符、\"
双引号、\r
回车符、\ooo
八进制数、
\t
横向制表符、\xhh
十六进制数、\v
纵向制表符
字符常量 '\0'
表示值为 0 的字符,也就是空字符(null)
通常用 '\0'
的形式代替 0,以强调某些表达式的字符属性,但其数字值为 0
常量表达式是仅仅只包含常量的表达式
这种表达式在编译时求值,而不在运行时求值
它可以出现在常量可以出现的任何位置,例如:
#define MAXLINE 1000
char line[MAXLINE + 1];
或
#define LEAP 1 /* in leap years */
int days[31 + 28 + LEAP + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31];
字符串常量也叫字符串字面值,是用双引号括起来的 0 个或多个字符组成的字符序列
例如:
"I am a string"
或
"" /* 空字符串 */
双引号不是字符串的一部分,它只用于限定字符串
字符常量中使用的转义字符序列同样也可以用在字符串中
在字符串中使用 \"
表示双引号字符
编译时可以将多个字符串常量连接起来,如下列形式:
"hello," " world"
等价于
"hello, world"
字符串常量的连接为将较长的字符串分散在若干个源文件行中提供了支持
从技术角度看,字符串常量就是字符数组
字符串的内部表示使用一个空字符 '\0'
作为串的结尾
因此,存储字符串的物理存储单元数比括在双引号中的字符数多一个
这种表示方法也说明,C 语言对字符串的长度没有限制,但程序必须在扫描完整个字符串之后才能确定字符串的长度
标准库函数 strlen(s)
可以返回字符串参数 s
的长度,但长度不包括末尾的 '\0'
下面是我们设计的 strlen
函数的一个版本:
/* strlen: return length of s */
int strlen(char s[])
{
int i;
while (s[i] != '\0')
++i;
return i;
}
标准头文件 <string.h>
中声明了 strlen
和其它字符串函数
我们应该搞清楚字符常量与仅包含一个字符的字符串之间的区别:'x'
与 "x"
是不同的
前者是一个整数,其值是字母 x
在机器字符集中对应的数值(内部表示值)
后者是一个包含一个字符(即字母 x
)以及一个结束符 '\0'
的字符数组
枚举常量是另外一种类型的常量
枚举是一个常量整型值的列表,如:
enum boolean { NO, YES };
在没有显式说明的情况下,enum
类型中第一个枚举名的值为 0,第二个为 1,依此类推
如果只指定了部分枚举名的值,那么未指定值的枚举名的值将依着最后一个指定值向后递增
参看下面两个例子中的第二个例子:
// 定义枚举类型 escapes
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t',
NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };
// 定义枚举类型 months
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC };
/* FEB 的值为 2,MAR 的值为 3,依此类推 */
enum months lastMonth; // 声明 enum months 类型的变量 lastMonth
enum
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; // 声明匿名枚举类型变量 workday
enum week { Mon = 1, Tue, Wed, Thu, Fri Sat, Sun } days; // 定义枚举类型 week,并声明 enum week 类型的变量 days
不同枚举中的名字必须互不相同,同一枚举中不同的名字可以具有相同的值
枚举为建立常量值与名字之间的关联提供了一种便利的方式
相对于 #define
语句来说,它的优势在于常量值可以自动生成
尽管可以声明 enum
类型的变量,但编译器不检查这种类型的变量中存储的值是否为该枚举的有效值
尽管如此,枚举变量提供了类型检查的机会(包含了可供检查的必要信息),因此通常比 #defines
更好
此外,调试程序可以以符号形式打印出枚举变量的值