操作符详解

目录

1.算数操作符

1-1. 取模/取余 %

1-2. 除法 /

2.移位操作符

2.1左移操作符

2.2右移操作符

2.2.1.算数右移(主要用来进行有符号位的倍增、减半)

2.2.2.逻辑右移(主要用来进行无符号位的倍增、减半)

3.位操作符

1.按位与

2.按位或

3.按位异或

4.赋值操作符

5.单目操作符

1.按位取反

2.逻辑反操作

6.关系操作符

7.逻辑操作符

8.条件操作符

9.逗号表达式

10.下标引用、函数调用、结构成员

1.下标引用操作符

2.结构体操作符

11.表达式求值

1.隐式类型转换

2.算数转换

12.操作符的属性


算数操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

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

1.算数操作符

+ - * / %

1-1. 取模/取余 %

得到的相除之后是余数 【取模负数】

取模操作符的两个操作数必须是整数

1-2. 除法 /

得到的是相除之后的商

(当除号两端都是整数,执行整数除法,两端只要有一个浮点数,执行浮点数除法)

2.移位操作符

(操作数只能是整数)

不要移动负数位!!!(标准未定义行为)

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

2.1左移操作符

将操作数在内存中存储的二进制位向左移动,后面补0

int a = 5;
00000000 00000000 00000000 00000101  // <- 对补码进行操作(内存存储的是补码,进行运算也使用补码,正整数的原反补相同)
int b = a << 1;
00000000 00000000 00000000 00001010  // <- 补码/原码
//(b = 10    *****左移操作符部分情况下相当于将操作数乘以2*****)
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

int a = -5;
11111111 11111111 11111111 11111011 // <- 补码
int b = a << 1;
11111111 11111111 11111111 11110110 // <- 补码	
10000000 00000000 00000000 00001010 // <- 原码
//(b = -10)

2.2右移操作符

(到底是算数右移还是逻辑右移,取决于编译器 ~ )

常见的编译器下都是算术右移

2.2.1.算数右移(主要用来进行有符号位的倍增、减半)

(右边丢弃,左边补符号位)

2.2.2.逻辑右移(主要用来进行无符号位的倍增、减半)

(右边丢弃,左边补0)

//正数的算数右移和逻辑右移是相同的

int a = 5;
00000000 00000000 00000000 00000101 <-对补码进行操作 右移一位,左边补符号位0
int b = a >> 1;
00000000 00000000 00000000 00000010 <- 补码 
//(b = 2    *****右移操作符部分情况下相当于将操作数除以2*****)
——————————————————————————————————————————————————————————————————————————————————————————————————————————————
//负数的算数右移

int a = -5;
11111111 11111111 11111111 11111011 // <- 补码
int b = a >> 1;
11111111 11111111 11111111 11111101 // <- 补码
10000000 00000000 00000000 00000011 // <- 原码
 //(b = -3)
 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————
 //负数的逻辑右移
 
int a = -5;
11111111 11111111 11111111 11111011 // <- 补码
int b = a >> 1;
01111111 11111111 11111111 11111101 // <- 补码
00000000 00000000 00000000 00000011 // <- 原码
 //(b = 3)

3.位操作符

(对两个操作数存在内存中的二进制补码进行操作)

&	按位与     |按位或     ^按位异或

1.按位与

(两个二进制序列,只要有0就为0,只有同为1时才为1)

【可以通过 a & 1,然后 a >> 1 ,来的到a的二进制序列的每一位】

2.按位或

(两个二进制序列,只要有1就为1,只有同为0时才为0)

3.按位异或

(两个二进制序列,相同为0,相异为1)

【不使用临时变量交换两个数——缺点:只能用于整数的交换,可读性低】

4.赋值操作符

赋值操作符 =  复合赋值符+=  -=  *=  /=  %=  <<=  >>=  &=  |=  ^=

a = x = y+ 1; 支持连续赋值但是不提倡

x = y + 1;

a = x; 这样写更加清晰且易于调试

3 = 1000;(报错:左操作数必须为左值)

左值,是可以放在等号左边的,一般是一块空间。

右值,是可以放在等号右边的,一般是一个值或者一块空间的内容。

5.单目操作符

//   !逻辑反操作  -负值  +正值  &取地址  sizeof计算操作数的类型长度(以字节为单位)  ~按位取反  
     --前置、后置--  ++前置、后置++  *间接访问操作符(解引用操作符)  (类型) 强制类型转换  

1.按位取反

int a = 10;

00000000000000000000000000001010

将这一位的二进制数字改成1

a |= (1 00000000000000000000000000000100 (1

在将刚才0改成的1,再改回0

将 (1 11111111111111111111111111111111111011 ~(1

2.逻辑反操作

printf("%d", !2);打印0,(!非零数)为假,为0

pirntf("%d", !0);打印1,(!0)为真,为1

6.关系操作符

>		>=		<		<=		!=		==

!!!注意 !!!

             ==

编译的过程中==和=不小心写错,程序会出错

7.逻辑操作符

&& 逻辑与             ||逻辑或

&& 左操作数为假右边不计算

| | 左操作数为真右边不计算

8.条件操作符

(exp1 ? exp2 :exp3) 三目操作符	

9.逗号表达式

exp1, exp2, exp3, ……expN

用逗号隔开的多个表达式

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

10.下标引用、函数调用、结构成员

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

1.下标引用操作符

arr[7] --> *(arr + 7) --> *(7 + arr) --> 7[arr]

通过上面推导得到 arr[7] 和 7[arr] 效果是一样的

2.结构体操作符

结构体变量.结构体成员

结构体指针->结构体成员

struct Stu { char name[20]; int age; double score; }; int main() { struct Stu s = {"zhangsan", 20, 85.5}; printf("%s %d %.2lf\n", s.name, s.age, s.score); struct Stu* ps = &s; printf("%s %d %.2lf\n", ps->name, ps->age, ps->score); return 0; }

11.表达式求值

1.隐式类型转换

c的整型算数运算至少以缺省整型类型的精度来进行计算

为了获得这个精度,表达式中字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

整型提升的意义:

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,

同时也是CPU的通用寄存器的长度。

依次,两个char类型的相加,在CPU执行实际上也要先转换为CPU内整型操作数的标准长度。

通用CPU是难以直接实现两个8比特字节直接相加运算(虽然及机器指令中可能有这种字节相加指令)。

所以,表达式中各种长度可能小于int长度的整型值,都想必须转换成int或unsigned int,然后才能送入CPU去执行运算。

char a = 0xb6; char b = 0xb600; char c = 0xb6000000; if(a == 0xb6) printf("a"); if(b == 0xb600) printf("b"); if(c == 0xb6000000) printf("c"); 结果为:c char 和 short 放不下数据 0xb6 会发生截断,那么a 和 b就不是 0xb6这个值了。

char c = 1; printf("%u\n", sizeof(c)); printf("%u\n", sizeof(+c)); printf("%u\n", sizeof(-c)); 输出结果为:1 4 4 因为c前面加了+或-就相当于参与运算,就会发生整型提升为int类型,所以结果为4。

2.算数转换

如果某个操作的各个操作数属于不同类型,那么除非其中一个操作数的类型转换为另一个操作数的类型,

否则操作无法进行。

下列层次体系称为寻常算数转换。

long double double float unsigned long int long int unsigned int int

12.操作符的属性

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

操作符的优先级

操作符的结合性(N/A 不考虑结合性)

是否控制求值顺序

表达式要确定唯一的计算路径,若计算路径不唯一,那么就是有问题的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值