《C程序设计语言(第2版·新版)》第2章 类型、运算符与表达式
类型:决定对象可取值的集合以及可执行的操作;运算符指定操作;表达式把变量和常量组合起来生成新值。
ANSI C修补:所有整型都包括signed和unsigned两种;浮点运算可单精度还可long double类型运算;字符串可以编译时连接;支持枚举类型;const类型;扩充算术类型的自动强制类型转换规则
2.1 变量名
将下划线看做字母;变量名是以字母开头的字母数字序列;库函数名字通常以下划线开头,不要用;区分大小写;传统上变量名用小写,符号常量名全大写,局部变量(尤其循环控制变量)一般短名,外部变量名字较长
2.2 数据类型及长度
基本:
char:字符型,占用一个字节,可存本地字符集中一个字符;
int :整型,通常反映所用机器中整数的最自然长度;
float:单精度浮点型
double:双精度浮点型
int前可加限定符short 或long, 此时int可省略;编译器根据硬件特性自主选择合适长度(short不长于int,int不长于long);通常short为16位,int为16或32位,long为32位;
限定符signed和unsigned可加在上述任何整型以及char前。8位 char, unsigned范围0~255,signed范围-128~127(采用对二补码的机器上);不带限定符的char是否带符号取决于机器,但可打印字符总是正值;
float、double、long double可表示相同长度也可表示两三种不同长度;
定义以上类型长度的符号常量及其他与机器和编译器有关的属性在<limits.h>及<float.h>中可以找到;
2.3 常量
1、2 、3 等整数常量属int型;大整数超出int范围,会被当做long处理;long类型以L或l结尾如123456789L;ul或UL结尾表示unsigned long;十进制31=八进制037=十六进制0x1f或0X1F;它们同样可加U、L等后缀;
123.4、1.5e-2等为double; 加f或F是float,加l或L是long double;(It:float相当于short,double相当于int, long double 相当于long)
字符常量如'x'是一个整数,其值为机器字符集中的数值,可与其他字符比较也可作为整数参与数值运算;
转义字符:'\v'、'\013'、'\xb'(纵向制表符的八进制(\ooo)和十六进制(\xhh)表示);空字符(null)为'\0',其值也为0,但其属性是字符;
常量表达式:只含常量,例如#define MAX 1000之后的char line[2+MAX+3];在编译时而非运行时求值(ps:博客中经测试,const变量也是如此)
字符串常量:类似""、" u r naive"等括在双引号内的字符序列。其内用\"表示双引号;编译时可将多个字符串常量连接,比如“hello, ”“world”等价于“hello, world”;字符串常量实则是字符串数组,内部表示中加'\0'结尾,故物理存储单元数多1;这也说明C中字符串长度无限制,确定其长度需扫描完该字符串;库函数strlen(s)(在中)可求s长度(不含'\0');
枚举常量:一个常量整型值列表,方便德建立常量值与名字得关系,可自动生成(#define 则不能)。例:
enum boolean { NO, YES };//自动从0开始赋值,NO=0, YES=1
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t'}:
enum months {JAN = 1, FEB, MAR, APR}; //未指定值将递增赋值;
之后可定义枚举变量enum months amonth; 则令amonth等于JAN, FEB等意义明显,也可赋其他整型值
2.4 声明
变量必须声明才能使用(有些可以通过上下文隐式声明);可声明一个变量表;可用表达式初始化;
非自动变量只能初始化一次且是常量表达式;
外部变量与静态变量默认被初始化为0;
显式初始化的自动变量每次都重新初始化(可以是任何表达式),未显式初始化的自动变量值未定义(即无效值);
const可限定任何变量声明,其指定变量的值不能修改;数组则所有元素都不能修改;以下函数不能修改数组元素的值: int strlen(const char[])
2.5 算术运算符
+ - * / %
二元,其中取模运算符%不能用于浮点数;有负操作数,结果取决于机器;
2.6 关系运算符与逻辑运算符
> >= < <= == != 后两个优先级较低;
&& 高于 ||;
! 逻辑非,一般用 if(!valid) 而不用 if(valid == 0);
2.7 类型转换
一般,自动转换把操作数“变宽”且不丢失信息;无意义表达式会报错(例如浮点数做下标);可能丢失信息的表达式(比如把长整型值赋给短整型量)会警告,但合法;
<ctype.h>中定义了一组与字符集无关的测试和转换函数(如tolower(c),isdigit(c)等);
C未指定char是否带符号(但保证了可打印字符为非负值),转为int与机器有关;
if, while, for 的测试部分,“真”与“非0”等价;
C中有很多隐式算术类型转换:两操作数不同则把“较低”类型提升到“较高”类型;包含unsigned类型时较麻烦,与机器有关;赋值时右边值需转变为左边类型;char, short总被转换为int,故相互赋值可能会丢失信息;float转int会截取;double转float截取或舍入取决于机器;
强制类型转换:(类型名) 表达式,是一个一元运算符,与其他一元运算符优先级相同;函数调用将进行自动强制类型转换;
2.8 自增、自减运算符
++n: n值增1后使用;n++:n值使用后增1;--类似;只能作用于变量;
2.9 按位运算符
6个,可作用于整型,即带符号或无符号的;
& | ^ << >> ~
常用来建屏蔽码(It: 操作数都作为二进制来运算)。左移补零;右移无符号补零,有符号取决于机器(分补符号位的“算术移位”和补零的“逻辑移位”)
2.10 赋值运算符与表达式
op=, 其中op可为 + - * / % << >> & ^ |
赋值表达式具有值,类型和值都是左操作数的结果;
2.11 条件表达式
expr1 ? expr2 : expr3
2.12 运算符优先级与求值顺序
1 括弧、访问结构:() [] -> .
2 前置: ! ~ ++ -- + - * & (type) sizeof
3 算术-乘除取模: * / %
4 算术-加减: + -
5 移位: << >>
6 关系-不等性: < <= > >=
7 关系-相等性: == !=
8 按位-与: &
9 按位-异或: ^
10 按位-或: |
11 逻辑-与: &&
12 逻辑-或: ||
13 条件表达式: ?:
14 赋值表达式: = += -= *= /= %= &= ^= |= <<= >>=
15 逗号表达式: ,
其中:
2与13结合性是从右至左,其他都是从左至右;
四个运算符(&& || ?: ,)的多个操作数有规定运算顺序,其他运算顺序以及函数各参数求值顺序也未规定,取决于编译器,因最佳求值顺序同机器结构有很大关系;
建议:避免特殊实现方式,除非了解机器;