前言:
在上文中,我们已经学习了 原码、反码、补码、移位 操作符、移位操作符、位操作符、逗号表达式、下标访问[ ]、函数调用( ),接下来我们将继续学习剩下的操作符。
1. 结构成员访问操作符
1.1 结构体成员的直接访问
结构体成员的访问是通过点操作符(.)访问的,点操作符接受两个操作数。
1.2 结构体成员的间接访问
有时候我们得到的不是一个结构体变量,而是得到了一个指向结构体的指针。我们就需要用到->进行访问结构体的成员。
具体可以参考:c语言结构体(初阶)-CSDN博客
2. 操作符的属性:优先级、结合性
c语言中有两个重要的属性:优先级、结合性,这两个属性决定了表示式求值的计算顺序。
2.1 优先级
优先级指的是:如果一个表达式含有多个运算符,哪个运算符应该优先执行。各种运算符的优先级是不一样的。
1 3 + 4 * 5
上⾯⽰例中,表达式 3 + 4 * 5 ⾥⾯既有加法运算符( + ),⼜有乘法运算符( * )。由于乘法
的优先级⾼于加法,所以会先计算 4 * 5 ,⽽不是先计算 3 + 4 。
2.2 结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符
是左结合,还是右结合,决定执⾏顺序。⼤部分运算符是左结合(从左到右执⾏),少数运算符是右结合(从右到左执⾏),例如 =
。在表达式如 a = b = c
中,首先执行 b = c
,然后将结果赋给 a
。
1 5 * 6 / 2;
上⾯⽰例中, * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执⾏,先计算 5 * 6 ,
再计算 6 / 2 。
运算符的优先级顺序很多,下⾯是部分运算符的优先级顺序(按照优先级从⾼到低排列),建议⼤概
记住这些操作符的优先级就⾏,其他操作符在使⽤的时候查看下⾯表格就可以了。
• 圆括号( () )
• ⾃增运算符( ++ ),⾃减运算符( -- )
• 单⽬运算符( + 和 - )
• 乘法( * ),除法( / )
• 加法( + ),减法( - )
• 关系运算符( < 、 > 等)
• 赋值运算符( = )
由于圆括号的优先级最⾼,可以使⽤它改变其他运算符的优先级。
3. 表达式的求值
3.1 整型提升
C语⾔中整型算术运算总是⾄少以缺省整型类型的精度来进⾏的。为了获得这个精度,表达式中的字符和短整型操作数在使⽤之前被转换为普通整型,这种转换称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执⾏,CPU内整型运算器(ALU)的操作数的字节⻓度⼀般就是int的字节⻓度,同时也是CPU的通⽤寄存器的⻓度。因此,即使两个char类型的相加,在CPU执⾏时实际上也要先转换为CPU内整型操作数的标准⻓度。
通⽤CPU(general-purpose CPU)是难以直接实现两个8⽐特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种⻓度可能⼩于int⻓度的整型值,都必须先转换为int或unsigned int,然后才能送⼊CPU去执⾏运算。
根据上述的运算规则,我们可以尝试计算一下如下表达式中c的值。
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d\n", c);
return 0;
}
其中a、b都是char类型变量,是1个字节,8bit位,那么a、b的补码就为:
a:00000011
b:01111111
在计算a + b时对a、b进行了整型(32bit位)提升所以得到:
a:00000000000000000000000000000011
b:00000000000000000000000001111111
相加之后得到:
00000000000000000000000010000010
所以c得到的补码就为:10000010,转为原码就为11111101,转位十进制得到c的结果就为:-126.
3.2 算术转换
如果某个操作符的各个操作数属于不同的类型,那么除⾮其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就⽆法进⾏。下⾯的层次体系称为寻常算术转换。
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。(就是由小到大进行转换)