C语言 ─── 操作符详解

目录

[1. 算术操作符](#1. 算术操作符)

[2. 移位操作符](#2. 移位操作符)

[2.1 左移操作符](#2.1 左移操作符)

[2.2 右移操作符](#2.2 右移操作符)

[3. 位操作符](#3. 位操作符)

[4. 复合赋值符](#4. 复合赋值符)

[5. 单目操作符](#5. 单目操作符)

[6. 逗号表达式](#6. 逗号表达式)

[7. 隐式类型转换](#7. 隐式类型转换)

[7.1 整型提升的意义:](#7.1 整型提升的意义:)

[7.2 如何进行整体提升呢?](#7.2 如何进行整体提升呢?)

[8. 算术转换](#8. 算术转换)

★★★数组名



**1.**算术操作符

cpp 复制代码
 +    -   *   /   %
  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

2. 移位操作符

cpp 复制代码
<< 左移操作符
>> 右移操作符
    
注:移位操作符的操作数只能是整数。

2.1****左移操作符

移位规则:
左边抛弃、右边补 0

2.2****右移操作符

移位规则:
首先右移运算分两种:

  1. 逻辑移位
    左边用0填充,右边丢弃
  2. 算术移位
    左边用原该值的符号位填充,右边丢弃

    警告⚠ :
    对于移位运算符,不要移动负数位,这个是标准未定义的。
    例如:
cpp 复制代码
int num = 10;
num>>-1;//error

3. 位操作符

位操作符有:

cpp 复制代码
& //按位与
| //按位或
^ //按位异或
注:他们的操作数必须是整数。

练习:
编写代码实现:求一个整数存储在内存中的二进制中1 的个数。

cpp 复制代码
#include <stdio.h>
int main()
{
     int num = -1;
     int i = 0;
     int count = 0;//计数
     for(i=0; i<32; i++)
     {
         if( num & (1 << i) )
         count++; 
     }
     printf("二进制中1的个数 = %d\n",count);
     return 0;
}
//思考还能不能更加优化,这里必须循环32次的。

#include <stdio.h>
int main()
{
     int num = -1;
     int i = 0;
     int count = 0;//计数
     while(num)
     {
         count++;
        //n=n&(n-1)执行一次可以把n的二进制最右面的1去掉一个
         num = num&(num-1);
     }
     printf("二进制中1的个数 = %d\n",count);
     return 0;
}
//这种方式是不是很好?达到了优化的效果,但是难以想到。

判断一个数是否为2的次方

cpp 复制代码
int main()
{
	int n;
	scanf("%d", &n);
	if ((n & (n - 1)) == 0)
	{
		printf("Yes ");
	}
	else
	{
		printf("No ");
	}
}

4. 复合赋值符

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

5. 单目操作符

! 逻辑反操作

  • 负值
  • 正值
    & 取地址
    sizeof 操作数的类型长度(以字节为单位)
    ~ 对一个数的二进制按位取反
    -- 前置、后置 --
    ++ 前置、后置 ++
    * 间接访问操作符 ( 解引用操作符 )
    ( 类型 ) 强制类型转换
    笔试题:
cpp 复制代码
#include <stdio.h>
int main()
{
    int i = 0,a=0,b=2,c =3,d=4;
    i = a++ && ++b && d++;
    //i = a++||++b||d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0;
}
//程序输出的结果是什么?

答案:1 2 3 4

1 3 3 5

6. 逗号表达式

cpp 复制代码
exp1, exp2,exp3,exp4,...expN

逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。 整个表达式的结果是最后一个表达式的结果。

7. 隐式类型转换

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

7.1 整型提升的意义

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

cpp 复制代码
//实例1
char a,b,c;
...
a = b + c;

b和 c 的值被提升为普通整型,然后再执行加法运算。
加法运算完成之后,结果将被截断,然后再存储于a中。

7.2 如何进行整体提升呢?

整形提升是按照变量的数据类型的符号位来提升的

cpp 复制代码
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

整形提升的例子 :

cpp 复制代码
//实例1
int main()
{
     char a = 0xb6;
     short b = 0xb600;
     int c = 0xb6000000;
     if(a==0xb6)
     printf("a");
     if(b==0xb600)
     printf("b");
     if(c==0xb6000000)
     printf("c");
     return 0;
}

实例1 中的 a,b 要进行整形提升 , 但是 c 不需要整形提升
a,b 整形提升之后 , 变成了负数 , 所以表达式 a==0xb6 , b==0xb600 的结果是假 , 但是 c 不发生整形提升 , 则表达式 c==0xb6000000 的结果是真 .
所程序输出的结果是:
c

cpp 复制代码
//实例2
int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));
 printf("%u\n", sizeof(+c));
 printf("%u\n", sizeof(-c));
 return 0;
}

实例2 中的 , c只要参与表达式运算,就会发生整形提升 , 表达式 +c , 就会发生提升 , 所以 sizeof(+c) 是 4 个字节.
表达式 - c 也会发生整形提升 , 所以 sizeof( - c) 是 4 个字节 , 但是 sizeof(c) , 就是 1 个字节 .

8. 算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。
下面的层次体系称为寻常算术转换

cpp 复制代码
long double
double
float
unsigned long int
long int
unsigned int
int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
警告:
但是算术转换要合理,要不然会有一些潜在的问题。

cpp 复制代码
float f = 3.14;
int num = f;//隐式转换,会有精度丢失

整形提升是针对小于int的值进行运算时需要整形提升,

算数转换最低也是int

★★★数组名

相关推荐
机器学习之心2 分钟前
一区北方苍鹰算法优化+创新改进Transformer!NGO-Transformer-LSTM多变量回归预测
算法·lstm·transformer·北方苍鹰算法优化·多变量回归预测·ngo-transformer
儿时可乖了5 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol6 分钟前
java基础概念37:正则表达式2-爬虫
java
yyt_cdeyyds12 分钟前
FIFO和LRU算法实现操作系统中主存管理
算法
xmh-sxh-131423 分钟前
jdk各个版本介绍
java
daiyang123...35 分钟前
测试岗位应该学什么
数据结构
alphaTao39 分钟前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
天天扭码42 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶42 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端