跳转到内容

2. 常量

常量(Constant)是程序中最基本的元素,有字符(Character)常量、整数(Integer)常量、浮点数(Floating Point)常量和枚举常量。枚举常量将在 第 3 节“数据类型标志”介绍。下面看一个例子:

c
printf("character: %c\ninteger: %d\nfloating point: %f\n", '}', 34, 3.14);

字符常量要用单引号括起来,例如上面的 '}' ,注意单引号只能括一个字符而不能像双引号那样括一串字符,字符常量也可以是一个转义序列,例如 '\n' ,这时虽然单引号括了两个字符,但实际上只表示一个字符。和字符串字面值中使用转义序列有一点区别,如果在字符常量中要表示双引号 " 和问号 ?,既可以使用转义序列 \"\? ,也可以直接用字符 " 和问号 ?,而要表示 '\ 则必须使用转义序列。[1]

计算机中整数和小数的内部表示方式不同(将在 第 14 章 计算机中数的表示 详细介绍),因而在 C 语言中是两种不同的类型(Type),例如上例的 343.14 ,小数在计算机术语中称为浮点数。这个语句的输出结果和 Hello world 不太一样,字符串 "character: %c\ninteger: %d\nfloating point: %f\n" 并不是按原样打印输出的,而是输出成这样:

bash
character: }
integer: 34
floating point: 3.14

printf 中的第一个字符串称为格式化字符串(Format String),它规定了后面几个常量以何种格式插入到这个字符串中,在格式化字符串中 % 号(Percent Sign)后面加上字母 cdf 分别表示字符型、整型和浮点型的转换说明(Conversion Specification),转换说明只在格式化字符串中占个位置,并不出现在最终的打印结果中,这种用法通常叫做占位符(Placeholder)。这也是一种字面意思与真实意思不同的情况,但是转换说明和转义序列又有区别:转义序列是编译时处理的,而转换说明是在运行时调用 printf 函数处理的。源文件中的字符串字面值是 "character: %c\ninteger: %d\nfloating point: %f\n"\n 占两个字符,而编译之后保存在可执行文件中的字符串是 character: %c 换行 integer: %d 换行 floating point: %f换行,\n 已经被替换成一个换行符,而 %c 不变,然后在运行时这个字符串被传给 printfprintf 再把其中的 %c%d%f 解释成转换说明。

有时候不同类型的数据很容易弄混,例如 "5"'5'5 ,如果你注意了它们的界定符就会很清楚,第一个是字符串字面值,第二个是字符,第三个是整数,看了本章后面几节你就知道为什么一定要严格区分它们之间的差别了。

习题

  1. 总结前面介绍的转义序列的规律,想想在 printf 的格式化字符串中怎么表示一个 % 字符?写个小程序试验一下。

    c
    #include <stdio.h>
    
    int main() {
        int percent = 50;
        printf("完成进度:%d%%\n", percent);  // 输出:完成进度:50%
        // printf("百分比:%d%\n", 50);  // 错误!编译器可能报错,因为 '%'
        // 后面没有合法的格式说明符
        return 0;
    }

  1. 读者可能会奇怪,为什么需要规定一个转义序列 \? 呢?因为 C 语言规定了一些三连符(Trigraph),在某些特殊的终端上缺少某些字符,需要用 Trigraph 输入,例如用 ??= 表示 # 字符。Trigraph 极不常用,介绍这个只是为了让读者理解 C 语言规定转义序列的作用,即特殊字符转普通字符,普通字符转特殊字符,? 也是一种特殊字符。极不常用的 C 语法在本书中通常不会介绍。 ↩︎