【C语言】操作符详解


一、算术操作符

+      —      *      /      %

1. 除了 % 操作符之外,其他几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符,如果操作符两边都是整数,则执行整数除法。而只要有一边是浮点数,则执行浮点数除法。
3. % 操作符的两个操作数必须是整数。返回的是整数之后的余数。


二、位移操作符

<< 左移操作符
>> 右移操作符

功能

位移操作符移动的是二进制,操作数只能是整数,整数在内存中存储的是二进制的补码,位移操作符移动的是存储在内存中的补码。

2.1、左移操作符

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 4;
    int b = a << 1;
    printf("%d %d", a, b); // 4 8
    return 0;
}
--------------------------
int main() {
    int a = -4;
    int b = a << 1;
    printf("%d %d", a, b); // -4 -8
    return 0;
}

左移:左边丢弃,右边补0

2.2、左移操作符

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 4;
    int b = a >> 1;
    printf("%d %d", a, b); // 4 2
    return 0;
}
-----------------------
#include <stdio.h>
int main() {
    int a = -4;
    int b = a >> 1;
    printf("%d %d", a, b); // -4 -2
    return 0;
}

1. 逻辑右移:右边丢弃,左边补0
2. 算术右移:右边丢弃,左边补原符号位
注意:采用逻辑右移与算术右移,取决于编译器,但是大部分编译器都采用的是算术右移,此实例也是采用算术右移

注意事项:

对于位移运算符,不要移动负数位,标准位定义。
num>>-1 // error


三、位操作符

&  按位与
|   按位或
^  按位异或
注意:他们的操作数必须是整数

3.1、& 按位与

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 3;
    int b = -5;
    int c = a & b;
    //00000000 00000000 00000000 00000011 -- 3的补码
    //11111111 11111111 11111111 11111011 -- -5的补码
    //00000000 00000000 00000000 00000011 -- 3
    printf("%d", c); // 3
    return 0;
}

按二进制位,有0为0,同1为1。

3.2、| 按位或

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 3;
    int b = -5;
    int c = a | b;
    //00000000 00000000 00000000 00000011 -- 3的补码
    //11111111 11111111 11111111 11111011 -- -5的补码
    //11111111 11111111 11111111 11111011 -- 3|-5的补码
    //11111111 11111111 11111111 11111010 -- 3|-5的反码
    //10000000 00000000 00000000 00000101 -- 3|-5的原码  -5
    printf("%d", c); // -5
    return 0;
}

按二进制位,有1为1。

3.3、^ 按位异或

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 3;
    int b = -5;
    int c = a ^ b;
    //00000000 00000000 00000000 00000011 -- 3的补码
    //11111111 11111111 11111111 11111011 -- -5的补码
    //11111111 11111111 11111111 11111000 -- 3^-5的补码
    //11111111 11111111 11111111 11110111 -- 3^-5的反码
    //10000000 00000000 00000000 00001000 -- 3^-5的原码  -8
    printf("%d", c); // -8
    return 0;
}

按二进制位,相同为0,相异为1。

3.4、扩展练习

不能创建临时变量(第三个变量),实现两个数的交换

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 3;
    int b = 5;
    a = a + b;
    b = a - b;
    a = a - b;
    printf("%d %d", a, b);
    return 0;
}

此方法若a和b两个数非常大,但没有超过整型大小,a+b超过了整型大小,所以存在缺陷。

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 3;
    int b = 5;
    a = a ^ b;
    b = a ^ b; // b = a ^ b ^ b --> b = a
    a = a ^ b; // a = a ^ b ^ a --> a = b
    printf("%d %d", a, b); // 5 3
    return 0;
}

异或是支持交换律:a ^ a = 0,0 ^ a = a


四、赋值操作符

=

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 10;
    int b = 0;
    int c = 30;
    a = b = c + 1; // 连续赋值
    printf("%d %d %d", a, b, c); // 31 31 30
    return 0;
}

赋值操作符连续赋值的前提是变量要初始化

4.1、复合赋值符

+=     -+     *=     /=     %=
>>=   <<=    &=     |=     ^=

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 10;
    a += 10; // --> a = a + 10
    printf("%d", a); // 20
    return 0;
}

这些运算符都可以写成复合的效果


五、单目操作符

!            逻辑反操作
-            负值
+           正值
&           取地址
sizeof        操作数的类型长度(字节单位)
~           对一个数的二进制按位取反
– –          前、后置- -
++          前、后置++
*            间接访问操作符
(类型)       强制类型转换

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 10; // 00000000 00000000 00000000 00001010
    int n = 3;
    a = a | (1 << (n-1)); // 按二进制数,把n位改为1
    printf("%d", a); // 14
    return 0;
}
------------------------------------
#include <stdio.h>
int main() {
    int a = 10; // 00000000 00000000 00000000 00001010
    int n = 2;
    a = a & ~(1 << (n - 1)); // 按二进制数,把n位改为0
    printf("%d", a); // 8
    return 0;
}

++和- -运算符

代码如下(示例):

#include <stdio.h>
int main() {
    int a = 10;
    int b = 10;
    int c = 10;
    int d = 10;
    printf("%d\n", ++a); // 11
    printf("%d\n", --b); // 9
    printf("%d\n", c++); //10
    printf("%d\n", c);   //11
    printf("%d\n", d--); //10
    printf("%d\n", d);   // 9
    return 0;
}

解析:

先对a进行自增,然后使用a,也就是表达式的值是a自增之后的值。a为11
先对b进行自减,然后使用b,也就是表达式的值是b自减之后的值。b为9
先对c使用,再增加,这样c的值是10;之后c变成11
先对d使用,再自减,这样d的值是10;之后d变成9


六、关系操作符

>  >=  <  <=  !=  ==

注意:

= 是赋值操作符, == 是等于操作符

七、逻辑操作符

&&   逻辑与
||     逻辑或

如何区分按位与逻辑与

1 & 2 --------- 0
1 && 2 ------- 1

如何区分按位或逻辑或

1 | 2 --------- 3
1 || 2 -------- 1

代码如下(示例):

#include <stdio.h>
int main()
{
	int i1 = 0, a1 = 0, b1 = 2, c1 = 3, d1 = 4;
	int i2 = 0, a2 = 0, b2 = 2, c2 = 3, d2 = 4;
	i1 = a1++ && ++b1 && d1++;
	i2 = a2++ || ++b2 || d2++;
	printf("a1 = %d\nb1 = %d\nc1 = %d\nd1 = %d\n", a1, b1, c1, d1); // 1 2 3 4
	printf("a2 = %d\nb2 = %d\nc2 = %d\nd2 = %d\n", a2, b2, c2, d2); // 1 3 3 4
	return 0;
}

解析:

1、a1 = 0,则a1++为假,由于是&&,所以b1、c1、d1的值不变
2、a2 = 0,则a2++为假,由于是||,所以b2的值变为3,由于a2++ || ++b2 为真,则d2的值不变


八、条件操作符

exp1 ? exp2 : exp3

代码如下(示例):

#include <stdio.h>
int main()
{
	int a = 4;
	int b = 0;
	/*if (a > 5)
		b = 3;
	else
		b = -3;*/
	b = a > 5 ? 3 : -3;
	printf("%d", b); // -3
	return 0;
}

九、逗号表达式

exp1,exp2,exp3……expN

代码如下(示例):

#include <stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = a + 10, b = a + 1);
	printf("%d", c); // 12
	return 0;
}

注意:

逗号表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果


十、下标引用、函数调用和结构体成员

[ ]   下标引用操作符
( )   函数调用操作符
.    结构体 . 结构体成员
->   结构体 -> 结构体成员

10.1、[ ]下标引用操作符

操作数:一个数组名+一个索引值

int arr[10];
arr和10都是操作数

10.2、( )函数调用操作符

代码如下(示例):

#include <stdio.h>
void test1()
{
	printf("hehe\n");
}
void test2(const char* str)
{
	printf("%s\n", str);
}
int main()
{
	test1(); //实用()作为函数调用操作符。
	test2("hello word");//实用()作为函数调用操作符。
	return 0;
}

10.3、访问一个结构体成员

代码如下(示例):

#include <stdio.h>
struct Book
{
	char name[20];
	int price;
};
int main()
{
	struct Book sb = { "C语言",60 };
	printf("%s %d", sb.name, sb.price); // C语言 60
	struct Book* ps = &sb;
	printf("%s %d", ps->name, ps->price); // C语言 60
	return 0;
}

十一、表达式求值

11.1隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

整形提升的意义:

表达式的运算要在CPU的相应运算器件中执行,CPU内整形运算器(ALU)的操作的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行是实际也要先转换为CPU内整形操作数的标准长度。
通用CPU是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整形值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

代码如下(示例):

#include <stdio.h>
int main()
{
	char a = 5;
	char b = 126;
	char c = a + b;
	// 00000000 00000000 00000000 00000101 -- 5
	// 00000101 -- a
	// 00000000 00000000 00000000 01111110 -- 126
	// 01111110 -- b
	//整形提升
	// 00000000 00000000 00000000 00000101 -- a
	// 00000000 00000000 00000000 01111110 -- b
	//+00000000 00000000 00000000 10000011 
	// 10000011 -- c
	printf("%d", c); // -125
	// %d以十进制的方式打印有符号整数
	// 11111111 11111111 11111111 10000011 -- c的补码
	// 11111111 11111111 11111111 10000010 -- c的反码
	// 10000000 00000000 00000000 01111101 -- c的原码 -125
	return 0;
}

注意:

1、负数的整形提升,高位补充符号位,即为1
2、正数的整形提升,高位补充符号位,即为0
3、无符号的整形提升,高位补0

代码如下(示例):

#include <stdio.h>
int main()
{
	char a = 5;
	printf("%d\n", sizeof(a));   // 1
	printf("%d\n", sizeof(a+1)); // 4
	printf("%d\n", sizeof(+a));  // 4
	printf("%d\n", sizeof(-a));  // 4
	return 0;
}

只要参与表达式运算,就会发生整形提升

实例代码:

#include <stdio.h>
int main()
{
	char a = 0xb6;
	// 10110110
	// 整形提升
	// 11111111 11111111 11111111 10110110 -- a的补码
	// 11111111 11111111 11111111 10110101 -- a的反码
	// 10000000 00000000 00000000 01001010 -- a的原码
	printf("%d ", a); // -74
	short b = 0xb600;
	// 10110110 00000000
	// 整形提升
	// 11111111 11111111 10110110 00000000 -- b的补码
	int c = 0xb6000000;
	// 10110110 00000000 00000000 00000000
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c"); // c
	return 0;
}

解析:

实例中a、b要进行整形提升,但是c不用整形提升
a、b 整形提升后为负数,所以表达式 a == 0xb6、b == 0xb600 的结果为假,c 不发生整形提升,所以 c == 0xb6000000的结果为真。

11.2、算术转换

某个操作符的各个操作数属于不同的类型,那么排名低的类型向排名高的类型转换

类型由低到高依次为:

int --> unsigned int --> long int --> unsigned long int --> float --> double --> long double

11.3、操作符的属性

复杂表达式求值的三个影响:

1、操作符的优先级
2、操作符的结合性
3、是否控制求值顺序

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柒个葫芦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值