第2章 类型、运算符与表达式
1.数据类型及长度
C语言只提供了下列几种基本数据类型:
char 字符型,占用一个字节,可以存放本地字符集(ANSI)中的一个字符
int 整型,通常反映了所有机器中整数的最自然长度
float 单精度浮点型
double 双精度浮点型
此外,还可以在这些基本数据类型之前加一些限定符。short和long两个限定符用于限定整型。int通常代表特定机器中整数的自然长度,如32位的计算机,int类型长度就为4个字节。short类型通常为16位,即2个字节,long类型通常为32位,int类型可以为16位或32位。个编译器可以根据硬件特性自主选择合适的类型长度,但要遵循以下限制:short与int类型至少为16位,而long类型至少为32位,并且short类型不得长于int类型,而int类型不得长于long类型。
signed和unsigned可用于限定char类型和任何整型,分别表示有符号数和无符号数。
long double类型表示高精度浮点数。同整型一样,浮点型的长度也取决于具体的实现。
2.常量
long类型的常量以字母l或L结尾,如123456789L。如果一个整数太大以至于无法用int类型表示时,也就被当做long类型处理。无符号常量以字母u或U结尾,如123U。后缀ul或UL表明是unsigned long类型。
浮点数常量包含一个小数点(如123.4)或一个指数(如1e-2,表示1×10-2),也可以两者都有。没有后缀的浮点数常量为double类型。后缀f或F表示float类型,而后缀l或L则表示long double类型。
整型数出了用十进制表示还可以用八进制和十六进制表示。带前缀0的整型常量表示八进制形式;前缀为0x或0X,表示十六进制形式。八进制和十六进制的常量也可以使用后缀L表示long类型,使用后缀U表示unsigned类型。例如,0XFUL是一个unsigned long类型的常量,其值等于十进制15。
一个字符常量是一个整数。
下面使用八进制和十六进制表示一个字符
‘/111’,表示一个字符,它的值是八进制0111,即十进制的73。
注意,只有斜线后边的数字个数小于等于3大于等于2,且每一位都在0-7之间它才表示一个八进制数。
‘/x11’,表示一个字符,它的值时十六进制0x11,即十进制的17。
ANSI C语言中的全部转义字符序列如下:
/a 响铃符 // 反斜杠
/b 退格符 /? 问号
/f 换页符 /’ 单引号
/n 换行符 /” 双引号
/r 回车符 /ooo 八进制数
/t 横向制表符 /xhh 十六进制数
/v 纵向制表符
常量表达式是仅仅包含常量的表达式。这种表达式在编译时求值。他可以出现在任何常量可出现的地方。
字符串常量也叫字符串字面值。是有双引号括起来的0个或多个字符组成的字符序列。
编译时可以讲多个字符串常量连接起来,如下:
“hello, ” “world”
等价于
“hello, world”
两个字符串之间可以存在多个空格。
枚举常量是另外一种另外一种类型的常量。枚举是一个常量整数值的列表,例如:
枚举为建立常量值与名字之间的关联提供了一种便利的方式。相对于#define语句来说,枚举的优势在于常量值可以自动生成。尽管可以声明enum类型的变量,但编译器不检查这种类型的变量中存储的值是否为该枚举的有效值。不过,枚举变量提供这种检查,因此枚举比#define跟具有优势。此外,调试程序可以以符号形式打印出枚举变量的值。
1. 声明
在C语言中所有变量都必须先声明后使用。
从概念上讲,外部变量和静态变量是在程序开始执行之前进行初始化,并且初始化表达式必须是常量表达式。若没有显式为外部变量和静态变量初始化,那么默认会被初始化为0。而对于自动变量,若为显式初始化,则它的值为未定义值(无效值)。
任何变量的声明都可以使用const限定符限定。该限定符指定变量的值不能被修改。对于数组而言,const限定符指定数组所有元素的值都不能被修改。const限定符也可配合数组参数使用,它表明函数不能修改数组元素的值。
4.运算符
运算符按照优先级大小由上向下排列,在同一行的运算符具有相同优先级。第二行是所有的一元运算符。
运算符 | 解释 | 结合方式 |
() [] -> . | 括号(函数等),数组,两种结构成员访问 | 由左向右 |
! ~ ++ -- + - * & (类型) sizeof | 逻辑非,位运算非,增量,减量,正负号,间接,取地址,类型转换,求大小 | 由右向左 |
* / % | 乘,除,取模 | 由左向右 |
+ - | 加,减 | 由左向右 |
<< >> | 左移,右移 | 由左向右 |
< <= >= > | 小于,小于等于,大于等于,大于 | 由左向右 |
== != | 等于,不等于 | 由左向右 |
& | 按位与 | 由左向右 |
^ | 按位异或 | 由左向右 |
| | 按位或 | 由左向右 |
&& | 逻辑与 | 由左向右 |
|| | 逻辑或 | 由左向右 |
? : | 条件 | 由右向左 |
= += -= *= /= &= ^= |= <<= >>= | 各种赋值 | 由右向左 |
, | 逗号(顺序) | 由左向右 |
我们要记住以下几点:
u 任何单目运算符的优先级高于双目运算符的优先级
u 何逻辑运算符的优先级要低于任何关系运算符
u 移位运算符的优先级比算术优先级低,但是比关系运算符高
u 逗号运算符的优先级最低,而赋值运算符的优先级仅高于逗号运算符
一个小例子:
printf("%d/n", 0<3<2);
输出结果为:1。
为什么?
因为关系运算符结合性是从左到右,那么0<3<2等价于(0<3)<2。0<3的值为1,然后1<2,所以最后的结果为1,即为真。
按位运算符
一元运算符~用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1.例如:
x = x & ~077;
将x的后6位设置为0。注意表达式x&~077与机器无关,他比形式为x&0177700的表达式要好,因为后者假定x是16位的数值。这种可移植的方式并没有增加额外的开销,因为~077是常量表达式,可以在编译时求值。
下面是几个有意思的函数: