常量的分类

类型 说明
int 类型常量 诸如 1234 一类的整数常量是 int 常量。
long 类型常量 以字母l或L结尾的整型常量。
无符号常量 以字母u或U结尾的整型常量。
浮点数常量 包含一个小数点(如123.4)或一个指数(如1e-2),也可以两者都有。没有后缀的浮点数常量为double类型。后缀f或F表示float类型,而后缀l或L则表示long double类型;
字符常量 一个字符常量是一个整数,书写时将一个字符括在单引号中,如x
字符串常量 用双引号括起来的0个或多个字符组成的字符序列。
枚举常量 一个常量整型值的列表

字符常量

一个字符常量是一个整数,书写时将一个字符括在单引号中,如,‘x’。字符在机器字符集中的数值就是字符常量的值。字符常量一般用来与其他字符进行比较,但也可以像其他整数一样参与数值运算。

某些字符可以通过转义字符序列(例如,换行符\n)表示为字符和字符串常量。转义字符序列看起来像两个字符,但只表示一个字符。另外,我们可以用\ooo表示 任意的字节大小的位模式 。其中,ooo代表1~3个八进制数字(0…7)。这种位模式还可以用\xhhh表示,其中,hh是一个或多个十六进制数字(0…9,a…f,A…F)。因此,我们可以按照下列形式书写语句:

1
2
#define VTAB '\013' /* ASCII vertical tab */
#define BELL '\007' /* ASCII bell character */

上述语句也可以用十六进制的形式书写为:

1
2
#define VTAB '\xb' /* ASCII vertical tab */
#define BELL '\x7' /* ASCII bell character */

ANSI C语言的全部转义字符序列如下所示:

转义字符 含义
\a 响铃符
\b 回退符
\f 换页符
\n 换行符
\r 回车符
\t 横向制表符
\v 纵向制表符
\\ 反斜杠
\? 问号
\' 单引号
\" 双引号
\ooo 八进制数
\xhh 十六进制数

字符常量\0表示值为0的字符,也就是空字符(null)。

字符串常量

  • 也叫字符串字面值,是用双引号括起来的0个或多个字符组成的字符序列。
  • 编译时可以将多个字符串常量连接起来,例如,下列形式:

1
"hello," " world"

等价于

1
"hello, world"

字符串常量的连接为将较长的字符串分散在若干个源文件行中提供了支持。

  • 从技术角度看,字符串常量就是字符数组。字符串的内部表示使用一个空字符\0作为串的结尾,因此, 存储字符串的物理存储单元数比括在双引号中的字符数多一个 。这种表示方法也说明,C语言对字符串的长度没有限制,但程序必须扫描完整个字符串后才能确定字符串的长度。标准库函数 strlen(s) 可以返回字符串参数s的长度,但长度不包括末尾的\0

下面是我们设计的strlen函数的一个版本:

1
2
3
4
5
6
7
8
9
/* 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的字符数组。

枚举常量

枚举是一个常量整型值的列表,例如:

1
enum boolean {NO, YES};

在没有显式说明的情况下,enum类型中第一个枚举名的值为0,第二个为1,依此类推。如果只指定了部分枚举名的值,那么未指定的枚举名的值将依着最后一个指定值向后递增,参看下面两个例子中的第二个例子:

1
2
3
4
5
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t',
NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC };
/* FEB的值为2, MAR的值为3, 依此类推 */

不同枚举中的名字必须互不相同。同一枚举中不同的名字可以具有相同的值。

enum vs. #define

枚举为建立常量值与名字之间的关联提供了一种便利的方式。相对于#define语句来说,它的优势在于常量值可以自动生成。尽管可以声明enum类型的变量,但编译器不检查这种类型的变量中存储的值是否为该枚举的有效值。不过,枚举变量提供这种检查,因此枚举比#define更具优势。此外,调试程序可以以符号形式打印出枚举变量的值。

const 常量

强烈建议在任何可能的情况下使用 const 。

任何变量的声明都可以用const限定符限定。该限定符指定的变量的值不能被修改。对数组而言,const限定符指定数组所有元素的值都不能被修改:

1
2
const double e = 2.71828182845905;
const char msg[] = "warning: ";

const限定符也可配合数组参数使用,它表明函数不能修改数组元素的值:

1
int strlen(const char[]);

如果试图修改const限定符限定的值,其结果取决于具体实现。

const vs. #define

C++ 语言可以用 const 来定义常量,也可以用 #define 来定义常量。但是前者比后者有更多的优点:

  1. const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
  2. 有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。

Comments