4.6.1 整型常量
在C语言里,变量有类型,值也有类型,给一个变量赋值,或者初始化它,值的类型必须和变量的类型相符。来看一个例子:
/****c0405.c****/ int main(void) { int m = 3700; return 0; }
在这个程序中,变量m的类型是int,需要初始化或者保存一个同类型的数值。那么,3700的类型也是int吗?还有return语句,它返回0值,这个0的类型和main函数的返回类型int一致吗?
在本书第1章里我们已经提到了常量和常量表达式,所以大家知道这里的3700和0就是常量。本质上,3700和0都是在程序编写时由程序员敲入的文字符号,与一般的文字符号相比,它们的不同之处是,在程序翻译期间,C实现会将它们识别并转换为整数,且不再可能发生改变,所以这些代表整数的符号称为整型常量。
如表4-1所示,整型常量有三种形式,包括十进制常量、八进制常量或者十六进制常量,区分它们的方法也很简单——观察其前缀。
表4-1 不同形式的整型常量
十进制形式的整型常量以非0数字字符开头,后面可以是从0到9的任意数字字符的组合;八进制形式的整型常量以数字0开头,后面可以是从0到7的任意数字字符的组合;十六进制形式的整型常量以“0x”或者“0X”开头,后面可以是以下字符的任意组合:从0到9的数字字符、从a到f的字母,以及从A到F的字母。
C语言里的数字(数值)都是有类型的,如果说整型常量的前缀决定了它的基数(采用的数制),那么后缀则指定了它的类型。后缀u或者U是“unsigned”的意思;后缀l或者L是“long”的意思;后缀ll或者LL是“long long”的意思。这几种后缀可以单独使用,也可以组合使用,但只有以下组合是允许的、有意义的:ul、uL、ull、uLL、Ul、UL、Ull、ULL、lu、lU、Lu、LU、llu、llU、LLu、LLU。
因此,2u、3U、0x3fu、0x6dLLu、073ull也都是整型常量,其类型分别为unsigned int、unsigned int、unsigned int、unsigned long long int和unsigned long long int。其他一些整型常量的例子见表4-1。
十进制常量不会以“0”打头,而八进制常量必须以“0”打头。经验不足的人可能以为数字前面的0不会改变数字的大小,一不留神将十进制常量写成八进制常量。
确定整型常量的类型实际上并没有那么简单,这要取决于值的大小、使用的基数、后缀和各种整数类型所能表示的值的范围(这取决于C实现)。从传统的K&R C开始,到C89,再到C99和C11,所使用的规则多少有些差别。表4-2给出了最新的类型确定规则。
表4-2 整型常量的类型对照表
根据整型常量所采用的后缀和基数,结合具体的C实现,从所对应的方框内挑选出第一个能够表示常量值的类型,可作为整型常量的类型。
例如,如果C实现将int和long int类型的最大值定为2147483647,而将long long int类型的最大值定为9223372036854775807,那么整型常量5000000000的类型是什么呢?因为它没有后缀,采用的基数是10(十进制),所以定位到对应的表格,第一个备选类型是int,但它表示不了这个数;第二个备选类型long int也表示不了这个数,只有第三个备选类型long long int可以表示,所以整型常量5000000000的类型是long long int。
回到本节开头的程序,现在我们知道,3700的0是int类型的整型常量,可以用来初始化int类型的变量或者给int类型的变量赋值。
顺便说一下,调试器GDB提供了一个ptype命令,可以返回表达式的类型信息,下面的调试过程演示了它的使用方法。
D:\>gdb -silent (gdb)ptype 0 type = int (gdb)ptype 0L type = long (gdb)ptype 5000000000 type = long long (gdb)
练习4.6
整型常量37、0x98L和056ULL是什么类型?请在GDB中验证你的结论。