首先讲述一下两个概念:左值和右值
左值就是能够出现在赋值运算符左边的东西,右值就是能够出现在赋值运算符右边的东西
算数操作符(+ - * / %)
- 除了 % 操作符,其他几个操作符都可以作用于整数和浮点数。
- 对于 / 操作符,如果两个操作数都是整数,则做整数除法。只要其中有一个是浮点数,就做浮点数除法。
- %操作符的两个操作数必须是整数。
移位操作符(<< >>)
左移:在左移中,值最左边的几位被丢弃,右边多出来的几个空位则由0补齐。
右移
- 逻辑移位:
左边移入的位用0填充,这样就面临一个问题,一个负数的最高位本来是1,因为右移且用0填充,导致它由一个负数变成了一个正数。
- 算数移位:
左边移入的位由原先改制的符号位决定,符号位为1,则用1填充,符号位为0,则用0填充。
注意:
- 移位操作符的两个操作符必须都是整数。
- 无符号整数进行的所有移位操作都是逻辑移位。
- 有符号整数的移位进行逻辑移位还是算数移位取决于编译器,所以,如果程序中使用了有符号数的右移操作,则该程序是不可移植的。
- 对于移位的位数是一个负数或者说位数比操作数的位数还要多,这种情况是未定义的,它的具体操作取决于编译器。应避免这种情况出现。
位操作符(& | !)
- & 按位与 对应相与的位都为1则结果为1,否则为0。1&1 = 1,1&0 = 0, 0&1 = 0, 0&0 = 0;
- | 按位或 只要对应相或的位有一位为1,则结果为1。1|1 = 1, 1|0 = 1,0|1 = 1, 0|0 = 0;
- ^按位异或 相异为1,相同为0. 1^0 = 1 , 0^1 = 1, 0^0 = 0, 1^1 = 0;
- 进行位操作的两个操作数必须是整数。
赋值操作符(=)
- 赋值操作符把右操作数的值存储于左操作数指定的位置。
- 需要注意的是,赋值也是一个表达式,只要是表达式就会具有一个值,,赋值表达式的值就是右操作数的值。
- 将一个整型赋值给一个字符型数据,该整形会被截断。这也是为什么getchar函数的返回值要是一个整型而不是字符类型的原因。EOF需要的位数比字符型值能提供的位数要多,当将EOF赋值给一个字符型数据,会把EOF截短。
复合赋值符(+= -= *= /= %= <<= >>= &= ^= |=)
单目操作符
! | 逻辑反操作 |
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
~ | 对一个数的二进制按位取反 |
-- | 前置、后置-- |
++ | 前置、后置++ |
* | 间接访问操作符 |
(类型) | 强制类型转换 |
说明:sizeof是操作符,不是函数!sizeof后边的括号是可以去掉的,而且在sizeof内部是不进行任何的算数运算的,只能用于求数据类型的大小。
当数组名单独出现在sizeof内部时,返回的是整个数组的大小,以字节为单位。
关系操作符(> < >= <= ==)
逻辑操作符(&& ||)
工作原理:短路求值
- &&操作符的左操作数总是先进行求值,如果它的值为真,接着对右操作数求值,两者都为真则返回真。如果左操作数的值为假,那么直接返回假,不会再对右操作数进行求值。
- || 操作符的左操作数为真,那么就不会再对右操作数求值,直接返回真。
条件操作符
exp?exp2:exp3
举个例子: a > b ? a : b ; 这个表达式的意思就是如果a大于b,那么表达式的值就是a,否则该表达式的值为b。
逗号表达式
自左向右依次进行求值,整个逗号表达式的值就是最后那个表达式的值。
下标引用 [ ]、函数调用 ( )
结构体成员的访问
- . 结构体 . 成员名
- ->结构体指针->成员名
操作符优先级
以下图片来自《C和指针》