C和指针学习笔记四:操作符和表达式

一、操作符

包括:算术操作符,移位操作符,位操作符,赋值操作符,单目操作符,关系操作符,逻辑操作符,条件操作符,下标引用,函数调用,结构体成员调用。

1、算术操作符

加、减、乘、除、取模(%)
取模的两个操作数只能是整型值。

2、移位操作符

左移位:<< 最左边几位丢弃,最右边几位补0;
右移位:>> (1)逻辑移位:最右边几位丢弃,左边补0;
(2)算术移位:最右边几位丢弃,左边符号位为0,则全移入0,为1则全移入1。

标准规定无符号数都执行逻辑移位,而有符号数执行的是逻辑移位还是算术移位由编译器决定,若移位的位数超过操作数的位数,则具体情况由编译器决定。

所以出现有符号数移位操作的程序是不可移植的。

3、位操作符

& | ^ (与,或,异或)
通常用于位操作,修改变量指定位的值。
举例:
value的第bit_number位置1:
value |= 1 << bit_number;
value的第bit_number位置0:
value &= ~ (1 << bit_number);
测试指定位是否为1,为1则表达式非0:
value &= 1 << bit_number;

4、赋值操作符

赋值是表达式的一种,而不是某种类型的语句,所以只要允许出现表达式的地方都可以进行赋值。

举例:
a = x = y + 3;
a和x被赋的值并不是同一个值
若x的长度不够,则x被赋予的y+3值会被截短,再存储于x中,之后这个被截短的值再被赋予到a中。

复合赋值符:+=,-=,|=等等,多使用可以使代码更简洁。

5、单目操作符

!; ++; -- ; + ;-; ~ ;& ;* ;sizeof ; (类型)

  • sizeof():判断操作数的类型长度,以字节为单位。
    sizeof (int):必须加括号;
    sizeof x:可以不加括号;

举例:
16位机器中:int arry[10];
则sizeof(arry)=20
sizeof(arry[0])=2
sizeof(arry)/sizeof(arry[0])=10,即数组中元素的个数。

sizeof(a = b + 3):sizeof可以判断表达式的长度,此时不需要求表达式的值,所以a并没有被赋值;表达式返回a的大小。

  • (类型):强制类型转换(cast),具有很高的优先级,所以注意:把强制类型转换放在表达式的前面只会改变第一个项目的类型,要操作整个表达式的话,就要加括号。
    float(a):获得a对应的浮点数值。

  • 增值++和减值--操作符。
    前缀操作符在变量被使用之前改变变量的值;
    后缀操作符在变量被使用之后改变变量的值。

举例:
c = ++a; d=a++;
其中,c得到a增加之前的值,d得到a增加之后的值。

前缀和后缀形式的增值操作都复制了一份变量值的拷贝,用于周围表达式的值是这份拷贝来的值(赋值表达式);
前缀形式,在变量值增加之后复制,后缀形式,在变量值增加之前复制。
因此这些操作符的结果不是被他们修改的变量,而是变量值的拷贝。
++a = 10;
这条语句时错误的,++a的结果是变量值的拷贝,不是变量a本身,因此无法向一个值进行赋值。

6、关系操作符

>;>=;<;<=;!=;==

关系操作符的结果是一个整型值,而不是布尔值,可以将结果赋值给整型变量。(C语言中没有布尔类型,所以用整数来代替,非0位真,0为假)

7、逻辑操作符

逻辑与&&,逻辑或||,都会控制表达式的顺序执行:
从左到右依次执行,&&若左操作数为假,则后续右操作数不再求值,整个表达式为假,||逻辑或同理。这个行为被称为“短路求值”(short-circuited evaluation)。

举例:
if(a<b && c>d)
if(a<b & c>d)

if(a && b)
if(a & b)
第一组语句的结果一样,因为关系操作符的结果只能是0或1,而第二组语句结果不一样,因为若a,b非0,则第一个一定为真,而a,b按位与的值并不一定非0,所以不一定为真。

8、条件操作符

expression1 ? expression2 : expression3
会控制子表达式的求值顺序,expression2和expression3只会执行其中一个。
b = a > 5 ? 3 : -20;
a > 5则b = 3,否则b = -20。
条件操作符的作用有时类似于if,else,且比它更简洁。

9、逗号操作符

expression1,expression2,expression3,......,expressionN
将多个表达式用逗号分开,并从左到右依次执行,整个表达式的值为最后那个表达式的值。

while(a = get_value(), count_value( a ), a>0)
{
  expression;
}

因为依次执行,所以用在循环语句的测试表达式中时,获得下一个测试值语句只出现一次,修改时只需要在一个地方修改,方便程序的维护。

二、表达式求值

  • 表达式的求值顺序由所包含操作符的优先级和结合性决定;
  • 求值过程中的类型转换。

1、隐式类型转换(implicit conversion)

  • 发生的情况:

    • 算术表达式或逻辑表达式的操作数类型不相同时;(执行常用算术转换,即usual arithmetic conversion)
    • 操作符两边的变量类型不相同时;
    • 函数调用时,实参与形参不匹配时;
    • return语句中表达式类型和函数返回值类型不匹配时。
  • 隐式转换规则
    long double
    double
    float
    unsigned long int
    long int
    unsigned int
    int
    排名较低的操作数首先转换为另一个操作数的类型,即低精度数像高精度数转换。
    但是,在32位机器上,int类型和long字长相同,这时unsigned int的精度就比long精度高。

  • 整型运算符的精度至少是缺省整型类型,则运算过程中,字符型和短整型在使用之前被转换成普通整型,这种转换过程被称为整型提升(integral promotion)。
    提升精度往往无害,但降低精度可能会导致问题,低精度类型可能不够大,不能容纳高精度的完整数据。

(1)算术转换

举例:

char a,b,c;
  statement;
  a = b + c;

首先,b和c的值被提升为整型,然后,执行加法运算,最后,将结果截短后赋值并存储于a中。

当然,也可以使用强制类型转换执行显示转换(explicit conversion):(int)a = b + c;

(2)显示转换

举例:

int a = 5000;
int b = 25;
long c = a * b;
  • 在32位机器上,int和long int都是32位,这段代码运行起来没有问题;但在16位机器上,int是16位,long是32位,a*b的值应该是int型,但由于数据类型不够大(max = 2^16 - 1 = 65535),所以发生溢出,c会被赋一个无意义的值,因此需要进行强制类型转换:
    long c = (long)a*b;

  • 注意:long c = (long)(a*b);是错误的,因为溢出在强制转换之前就已经发生了,所以这样做不会有任何改变。

  • 数据溢出:

    • 有符号数的数据溢出是未定义的;
    • 无符号数的数据溢出:溢出后的数以2^(8*sizeof(type))作模运算。比如用unsigned char型变量存储258,其实存进去的是258-2^8=2。

(3)操作符两边表达式的转换

举例:

unsigned int a = 6;
int b = -20;
int c = (a + b) > 6 ? 1 : 2;

在加法运算中a和b类型不一致,会发生隐式转换,将int型转换为unsigned int型,b=-20转换为无符号数会变成一个很大的整数,因为无符号负数转换为的正数是用负数的补码所表示的,正数的源码,反码,和补码相同。所以,程序输出1,而不是2。

举例:

if(strlen(arry) < 10)
if(strlen(arry) - 10 < 0)

这两条语句不等价,因为strlen函数返回值是unsigned int型,两个无符号数运算所得的结果仍为无符号数,而无符号数肯定大于0。所以,要尽量避免使用第二个表达式。

2、操作符的优先级

表达式的运算规则:
两个相邻操作符的执行顺序由他们的优先级决定,若优先级相同,则由他们的结合性决定。
结合性:当多个相同优先级的运算符出现在表达式中时,先执行左边的叫具有左结合性,先执行右边的叫具有右结合性。

  • 举例:

a*b + c*d + e*f

相邻的加法和乘法运算符中,乘法运算符先执行;两个加法运算,根据加法的左结合性,是左边的加法运算先执行。但对于哪个乘法运算先执行,以及是否在所有乘法执行完后再执行加法运算,这些都由编译器决定,所以表达式就会有多种执行顺序。

c + --c

相邻的+和--操作符是--先执行,但对于表达式c和--c并不知道哪个先执行,又因为--c具有副作用,所以这两个表达式的执行顺序会对结果有影响。

  • 编译器只要不违背优先级和结合性规则,就可以任意决定复杂表达式的取值顺序。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容