1.数据类型和尺寸
1.1.对基本类型可应用一些限定符,如short int = short,long int = long
。
1.2.short
一般16
比特。int
可为16
或32
比特。long
至少是32
比特。
1.3.unsigned/signed
修饰char
及任何整型。char
到底是有符号还是无符号取决于机器实现。
1.4.float/double/long double
尺寸取决于机器实现。
2.常量
2.1.int
型常量,例1234
。
2.2.long
型常量,例1234l
或1234L
。
一个整型常量太大,越出int
时,会被当成long
对待,例12345678
。
2.3.无符号int
常量,例1234u
或1234U
。
2.4.无符号long
常量,例1234ul
或1234UL
。
2.5.double
常量,例123.4
或1e-2
。
2.6.float
常量,例123.4f
或1e-2f
或 123.4F
或1e-2F
。
2.7.long double
常量,例123.4l
或1e-2l
或 123.4L
或1e-2L
。
3.整型常量可采用8
进制,16
进制方式指定。
10
进制的31
,等价于8
进制的037
,等价于16
进制的0x1f
或0x1F
;
8
进制和16
进制常量也可以后根L
来表示long
,和U
来表示unsigned
例:0XFUL
等价于10
进制的15UL
。
4.字符常量是整数,单引号内加字符。字符常量值是字符在机器的字符集里面的数值。
例:在ASCII
字符集,字符常量'0'
有值为48
。字符常量参与数值操作,以整数方式。
在字符串和字符常量中,特定字符可以被转义序列表达,如\n
,看起来像是两个字符,但只代表一个。
此外,任意比特大小的位模式可以被指定
通过'\ooo'
,ooo
可以是1
个到3
个8
进制数
通过'\xhh'
,hh
可以说一个或多个16
进制数。
转义序列集合:
字符常量'\0'
代表字符,具有值0
,也即null
字符。
一个常量表达式是一个表达式,只涉及常量。这样的表达式可能在编译而非运行时被求值。
一个字符串常量或字符串文字,是0
个或多个被双引号环绕的字符的序列。
如:"I am a string" or "" /* the empty string */
双引号不属于字符内容,仅用来界定。
字符串是一个字符数组,由'\0'
来终止。
注意区分,一个字符常量和只含一个字符的字符串。例:'x'
和"x"
。
前者是一个整数,用于产生字符x
在机器字符集里的数值。后者是一个字符数组,包含一个字符,'x'
,和一个'\0'
.
有一类常量,枚举常量。枚举是常量值的列表。
5.声明
所有变量,在使用前需要声明。特定声明,可能隐含表示。
一个声明,指定一个类型,且包含一个或多个那类型变量的列表。
一个变量也可能在声明时被初始化。如果声明,跟着一个等号和一个表达式,表达式就相当于一个初始化器.
5.1.如果变量不是自动变量,初始化仅被执行一次,概念上,在程序开始执行前。且初始化器必须是一个常量表达式。
5.2.一个显式初始化的自动变量,每次它所在的函数或块进入时,被初始化一次。且初始化器可能是任何表达式。
5.3.全局和静态变量,默认被初始化为0
。
5.4.自动变量,未显式初始化的,含有未定义的值。
6.算术运算
6.1.+,-,*,/,%
.
6.2.%
不能被应用于float
或double
,对于/
截断方向和对%
结果符号,取决于机器。
7.关系和逻辑操作
7.1.>,>=,<,<=,==,!=,&&,||,!
.
7.2.由&&
和||
连接的表达式,按从左到右进行求值,一旦结果已知,求值停止。
8.类型转换
一个表达式中存在隐士的类型转换,一个表达式包含多项类型时,多个独立的项会被转换为统一的类型再进行运算,常见的包含不同整型或包含整型和浮点时,短整型会向可以包含它的长整型转换,整型会向浮点类型转换。char
可能被实现为无符号,或有符号类型。
可见的字符,在字符集中一般令其最高位为0
,故在无符号或有符号实现下,当char
转为int
时,结果int
都是正的。但char
中包含其他非可见字符时,最高为1
时,在转换为int
时,得到的是一个负数还是整数,依赖于char
被实现为有符号还是无符号。为了避免这类情形下的不确定,可以显式使用signed char
,unsigned char
.
类型转换,先不考虑有符号和无符号。首先对整型来说,每个整型有存储尺寸,而这在不同机器上是不同的。假设一个运算涉及n
个整型操作数,其中各个整型数中假设尺寸最大的为类型t
。则,第一步,先确定所有操作数的统一类型。原则为:
1.对n
个类型进行排序,取出最大类型。
2.所有类型先转化为最大类型再参与运算。
排序规则:
1.若类型A
尺寸小于类型B
尺寸,则A
小于B
2.类型A
的有符号<
类型A
的无符号
如这样得出的类型尺寸小于int
,直接将所有类型转化为int
参与运算。
对于赋值或者强制类型转换,按指定的目标类型进行转换。出现大类型转到小类型时,存在信息丢失问题。
9.自增,自减
++/-- A
或 A++/--
作为一个整体是一个表达式,存在一个表达式结果。
后++/--
版本,整体表达式的值是未被改变的值。而变量值在操作后发生了自增/
减1
;
前++/--
版本,整体表达式的值是改变后的变量值。变量值在操作后发生了自增/
减1
.
自增,自减运算符只能用于变量.
10.比特位操作
只能作用于整型操作数(带符号或无符号的char/short/int/long
)
(1). &
:与.
(2). |
:或.
(3). ^
:异或.
(4). <<
:左移.
(5). >>
:右移.
(6). ~
:取反.
11.赋值运算符和表达式
对+、-、*、/、%、<<、>>、&、^、|
,expr1 op= expr2
等价于expr1 = (expr1) op (expr2)
。
例子:x * = y + 1
含义是x = x * (y+1)
而不是x = x*y + 1
。
赋值表达式,作为一个整体的类型是左边操作数的类型,结果是复制后的结果。
12.条件表达
expr1 ? expr2 : expr3
。expr1
为true
时,expr2
被求值,结果作为表达式结果返回。expr1
为false
时,expr3
被求值,结果作为表达式结果返回。当expr2
结果和expr3
结果类型不一致时,无论expr1
是true
还是false
,表达式结果类型均为expr2
,expr3
两者中类型大的那个。
13.求值的优先级和顺序
对&&、||、?:
,操作数的求值顺序是被指定的。这属于语言陷阱,要避免因此而导致的不确定的代码。其他运算符的情形下,参与运算的各个操作数的求值顺序是没有明确要求的,取决于实现。类似的,调用多个形参的函数时,多个实参的求值顺序也是没有明确要求的。
// 该调用,多个实参求值顺序不同时,将产生不一致的结果,是要避免的。
printf("%d %d\n", ++n, power(2, n));
// 左右两边求值顺序不同时,产生不同结果。
a[i] = i++;