C语言中提供了多种类型的操作符可供我们进行使用,合理使用操作符可以大大增加代码的可读性和效率,所以正确且全面地认识操作符地类型和使用方法是极其重要的。
目录
一、操作符分类
操作符又名为运算符,这两种说法指向的都是下面所说的符号。接下去的内容说法都为操作符。
操作符分为:算术操作符,移位操作符,位操作符,赋值操作符,单目操作符,关系操作符,逻辑操作符,条件操作符,逗号表达式,下标引用、函数调用和结构成员。
操作符左右两端都可为操作数,或者只有其中一端为操作数。操作符便是对操作数进行相对应的操作。所以我们又可以根据操作符操作的操作数个数将操作符分为:单目操作符,双目操作符,三目操作符。
接下来将详细展开对每一种类型的说明。
二、算术操作符
算术操作符包括:+,-,*,/,%
上述这些都是我们耳熟能详的操作符,平时使用到的场景十分广泛。其中较易混淆的便是 / 和 % 这两个。
/ 相当于➗,得到的结果是商。如果 / 两边的操作数都是整数的话,那么进行的就是整数除法,得到的商就是整数。(例如:5 / 2 = 2,而不会出现浮点数的结果,商的结果是取其整数部分)只要其中一个操作数是浮点数,那么进行的便是浮点数除法。(例如:5.0 / 2 = 2.5)
% 叫做取余(或者取模)符号,顾名思义是取余数作为结果。这个操作符的两端的操作数必须都为整数,返回的是整除之后的余数。(例如:5 % 2 = 1)
三、移位操作符
移位操作符只有两种:左移操作符,<< 和 右移操作符,>> 。移位操作符的操作数只能是整数。
所谓移位,是对操作数的二进制位数进行移位操作。
整数在内存中是以二进制的形式存储的,表示方式有:原码,反码,补码三种。
正整数以上的三种形式相同。而负整数这三种类型就要进行相应的计算才能得出。整型 int(默认为有符号类整型) 占 4 个字节,所以共有32个二进制位,最高位是符号位。最高位为 0 表示为正整数,1 则表示为负整数。
例如:10,在内存的二进制表示为 00000000 00000000 00000000 00001010,这就是整数 10 的原码,并且由于他的原码、反码和补码三种形式相同,所以这也是他的反码和补码。
再如 -10,在内存中的二进制原码为 10000000 00000000 00000000 00001010。而他的反码就是对原码进行如下操作:符号位不变,其他位按位取反。即为 11111111 11111111
11111111 11110101。而补码则是反码进行 +1,便是 11111111 11111111 11111111 11110110
而补码想要还原成原码,可以对上述操作进行逆操作:-1 之后按位取反(除了符号位)。或者可以继续按位取反(除了符号位)之后再 +1 也可还原为原码。
那么这些表达形式有什么不同和意义呢?原码,其实就是我们所能看到的形式,例如我们在打印的时候,我们所能看到打印出来的结果,就是计算机按照原码转换为我们想要打印出来的格式所打印出来的。例如:-10,我们想要按照 %d (也就是十进制数的形式)打印出来,那么计算机就是按照 -10 的原码转换为十进制数然后进行打印,所以我们最后看到打印出来的结果是十进制数 -10 。而补码则是这个整数 -10 在内存存储的方式,也就是说这个十进制数在内存是以他的二进制补码的形式进行存储的。
之所以要使用补码的形式进行存储,是因为原码不能够直接参与计算。假如直接拿 10 和 -10 的原码进行加法计算,结果会发现明显不是 0 ,所以要转换为补码,这样进行运算时才不会出现错误。
左移操作符(<<)就是将二进制序列向左移动一位,规则为:左边抛弃,右边补 0 。也就是移动之后左边多出的一位将其丢弃,然后在最右边的空缺位上补上 0 。
右移操作符(>>)
首先右移运算分为两种:逻辑移位和算术移位。具体使用哪种运算取决于编译器,但正常情况下,算术移位比较常见。
1.逻辑移位:左边用 0 填充,右边丢弃。
2.算术移位:左边用原值的符号位填充,右边丢弃。
对于移位操作符,不要移动负数位(例:num<< -1),因为这个是标准中未定义的。并且最好一次性不要移动过多位数。
四、位操作符
位操作符有:&(按位与)、|(按位或)、^(按位异或)。他们的操作数也必须是整数,因为他们也是对整数的二进制位进行操作。
&,按二进制位进行“ & ”操作:对应的二进制位有0,则为0,两个同时为1,才为1。
|, 按二进制位进行“ | ”操作:对应的二进制位有1,则为1,两个同时为0,才为0。
^,按二进制位进行异或操作:相同为0,相异为1。
按位异或是个非常神奇的操作符,可以用它进行一些让人感觉不可思议的操作,如下:
//在不创建临时变量的前提下交换两个变量的值
int main()
{
int a = 10;
int b = 20;
printf("%d %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d %d\n", a, b);
return 0;
}
上述代码的原理在于:a ^ a = 0; 0 ^ a = a;
一个整型变量跟自己进行异或操作,结果为0。一个整型变量跟0进行异或,结果为变量自己。而且异或操作满足交换律和结合律。
所以如果将第一步代入第二步中:b = a ^ b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a
第一步和第二步同时代入第三步中:a = a ^ b = (a ^ b) ^ b = a ^ b ^ a = a ^ a ^ b = 0 ^ b = b
在不同场景下使用异或会达到一些意想不到的效果,但是一般可读性都比较差。
五、赋值操作符
= ,赋值操作符,这是个十分常见的操作符,同时也是个很棒的操作符,当我们对于某一个变量的值不满意时,可以直接使用此操作符进行修改。
由这个操作符,可以派生出很多复合操作符:+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=
复合操作符就是进行复合操作的,例如:
int x = 10;
//以下两个操作相同,其他操作符也是同理
x = x + 10;
x += 10;
六、单目操作符
上述提到的操作符都是双目操作符,需要两个操作数。而下列的单目操作符则只需要一个操作数:
!(逻辑反操作)、-(负值)、+(正值)、&(取地址)、sizeof(计算操作数的类型长度,单位为字节)、~(对一个数的二进制补码按位取反,操作数只能为整数)、- -(区分前置后置)、++(区分前置后置)、*(解引用操作符)、()(强制类型转换,括号内为数据类型)。
由于篇幅过长,内容分为上下两部分。如若内容有误,劳烦各位指出,本人确认之后定会修改。欲知后事如何,请听下回分解。