【C语言】/*操作符(下)*/

目录

一、操作符的分类

二、二进制和进制转换

        2.1 进制

        2.2 进制之间的转换

三、原码、反码、补码

四、单目操作符

五、逗号表达式

六、下标引用操作符[]

七、函数调用操作符()

八、结构体成员访问操作符

        8.1 直接访问操作符(.)

        8.2 间接访问操作符(->)

九、操作符的属性:优先级、结合性

        9.1 优先级

        9.2 结合性 

十、表达式求值

        10.1 整型提升

        10.2 算数转换

十一、问题表达式

        11.1 示例1

                 11.2 示例2

        11.3 示例3

        11.4 示例4

        11.5 总结 


一、操作符的分类

算术操作符: + 、- 、* 、/ 、%

移位操作符: <<、>>

位操作符: &、|、^

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

单⽬操作符: !、++、--、&*、+、-~ sizeof、(类型)

关系操作符: > 、>= 、< 、<= 、 == 、 !=

逻辑操作符: && 、||

条件操作符: ?  :

逗号表达式:

下标引⽤: [] 

函数调⽤: () 

结构成员访问:->

二、二进制和进制转换

2.1 进制

1. 其实我们经常能听到2进制、8进制、10进制、16进制这样的讲法,那是什么意思呢?其实2进制、8进制、10进制、16进制是数值的不同表⽰形式⽽已

2. 数值15的各种进制的表⽰形式:

    15的2进制:1111

    15的8进制:17

    15的10进制:15

    15的16进制:F

3. 

4. 二进制的每一位只能是:0~1(满2进1)

    八进制的每一位只能是:0~7(数字描述八进制会以0开头)

    十进制的每一位只能是:0~9

    十六进制的每一位只能是:0~9,A~F/a~f (数字描述十六进制会以0x/0X开头)

2.2 进制之间的转换

1. 2进制转10进制:2进制的每⼀位的权重,从右向左是: 2^0 , 2^1 , 2^3 ... 要计算一个二进制的十进制表示形式是多少,按如下图所示的方法计算即可 (二进制的每一位乘以对应权重再加起来即可)。

2. 10进制转2进制:(让10进制数除2直到余数是0/1为止,再从下至上取余数即可)

3. 2进制转8进制:(将二进制从右向左3个3个划分为一组,不够的补0,每三个二进制数经过转换后就是一个8进制数,转换的方法如下图,每三个二进制位分别乘以421加起来就是转换的一个八进制位)

4. 2进制转16进制:(将二进制从右向左4个4个划分为一组,不够的补0,每四个二进制数经过转换后就是一个16进制数,转换的方法如下图,每四个二进制位分别乘以8421加起来就是转换的一个16进制位)

三、原码、反码、补码

1. 整数的2进制表⽰⽅法有三种,即原码、反码和补码。

2. 有符号整数的三种表⽰⽅法均有符号位和数值位两部分2进制序列中,最⾼位的1位是被当做符号位,剩余的都是数值位,符号位⽤0表⽰“正”,⽤1表⽰“负”

3. 正整数的原、反、补码都相同

4. 负整数的三种表⽰⽅法各不相同

5. 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。

    反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

    补码:反码+1就得到补码。

6. 例如:-10存放在整型变量a中,即用4字节来存放整型-10

    原码:10000000 00000000 00000000 00001010

    反码:111111111 111111111 111111111 111110101

    补码:111111111 111111111 111111111 111110110

6. 补码得到原码也是可以使⽤:符号位不变,其他位按位取反,+1的操作。

7. 对于整形来说:整型数据存放内存中存放的是补码,在计算的时候也是用补码来计算的,为什么呢?

    答:在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀ 处理;同时,加法和减法也可以统⼀处理(CPU只有加法器),此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

四、单目操作符

1. 单⽬操作符: !、++、--、&*、+、-~ sizeof、(类型)

2. 单⽬操作符的特点是只有⼀个操作数。

3. 单目操作符&,名为取地址操作符,利用它就可以得到一个变量的地址,用printf打印地址时,用占位符%p(%p是以16进制形式打印地址,一个16进制位表示4个二进制位,例如,0x00AFF760用二进制表示为0000 0000 1010 1111 1111 0111 0110 0000);取地址得到的地址是变量开辟的所有内存单元中的最低的地址,因为知道最低的地址,变量所开辟的其他内存单元的地址顺藤摸瓜就能找到。

4. 单目操作符*,名为解引用操作符,它的操作数通常为一个指针变量,如果想要通过指针变量中的地址找到地址所指向的变量,可以通过对指针变量解引用就能找到,例如:int a = 10; int* pa = &a; 这两句代码中如果对变量pa进制解引用,则*pa就是变量a,对*pa赋值相当于对变量a赋值。

5. 单目操作符~,名为按位取反操作符,它的操作数必须是整型,对0按位取反的结果是-1

6. 温馨提示:橙色部分的单目操作符在【C语言】/*操作符(上)*/-CSDN博客 中已经讲解过了。

五、逗号表达式

1. 逗号表达式的语法形式:exp1, exp2, exp3, …expN (就是用逗号隔开的多个表达式)

2. 特点:从左向右依次执⾏,整个表达式的结果是最后⼀个表达式的结果。( 注意每个表达式都会计算哦!!!)

3. 示例1:下列为伪代码

        a = get_val();
        count_val(a);
        while (a > 0)
        {
                    //业务处理
                    a = get_val();
                    count_val(a);
        }

4. 上面的伪代码,我们会发现第1、2行和6、7行这样写会有些冗余,学习完逗号表达式后,我们可以将代码改进为:

    while (a = get_val(), count_val(a), a>0) 

    { 

             //业务处理

    }

//示例2:
#include <stdio.h>
int main()
{int a = 1;int b = 2;int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式//         0        12      12      13    printf("c = %d\n", c);//13return 0;
}
//示例3:
#include <stdio.h>
int main()
{int a = 1;int b = 2;int c = 3; int d = 4;if (a = b + 1, c = a / 2, d > 0)//a=3,c=1,1printf("hehe\n");//打印hehereturn 0;
}

六、下标引用操作符[]

1. 下标引用操作符[]有两个操作数

2. 语法形式:⼀个数组名[⼀个索引值]

3. 例如:

    int arr[10];//创建数组

   arr[9] = 10;//使用下标引⽤操作符访问数组元素,[ ]的两个操作数是arr和9

七、函数调用操作符()

1. 函数调用操作符()可以接受⼀个或者多个操作数,第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。(函数调用操作符最少有一个操作数)

2. 函数调用时:Add(x, y);//这里的()就是函数调用操作符

    函数定义时:void Mul(int x, int y);//这里的()是函数调用操作符

    函数声明时:extern Sub(int x, int y);//这里的()也是函数调用操作符

八、结构体成员访问操作符

8.1 直接访问操作符(.)

1. 使用场景:当我们知道结构体变量名时,想要找到它的成员变量,可以对结构体变量使用直接访问操作符(.)来找到它的成员变量。

2. 语法形式:结构体变量.成员名

3. 举例:如下图代码

#include <stdio.h>
struct Point
{int x;int y;
} p = { 1,2 };int main()
{printf("x: %d\ny: %d\n", p.x, p.y);//使用(.)找到p中的成员变量return 0;
}

8.2 间接访问操作符(->)

1. 使用场景:当我们只知道存放着结构体变量地址的指针变量时,想要找到该指针变量中地址所指向的结构体变量的成员变量,可以对该指针变量使用间接访问操作符(->)来找到成员变量。

2. 语法形式:结构体指针->成员名

3. 举例:如下图代码

#include <stdio.h>
struct Point
{int x;int y;
};
int main()
{struct Point p = { 3, 4 };struct Point* ptr = &p;ptr->x = 10;ptr->y = 20;printf("x = %d\ny = %d\n", ptr->x, ptr->y);//相当于ptr找到它所指向的p的成员x、yreturn 0;
}

九、操作符的属性:优先级、结合性

操作符的优先级和结合性决定了表达式求值的计算顺序

9.1 优先级

1. 概念:优先级讨论的是,如果⼀个表达式包含多个操作符,哪个操作符应该优先执⾏的问题。

2. 例如表达式 3 + 4 * 5 ⾥⾯既有加法操作符( + ),⼜有乘法操作符( * ),由于乘法的优先级⾼于加法,所以会先计算 4 * 5 ,⽽不是先计算 3 + 4 。

3. 优先级起作用的条件:对象:相邻操作符,效果:优先级高的先执行

4. 由于圆括号的优先级最高,因此在实际应用过程中可以使用它改变其他操作符的优先级

9.2 结合性 

1. 概念:如果两个操作符优先级相同,优先级是没办法确定先计算哪个得,这时候就得看结合性,根据操作符是左结合,还是右结合,决定执⾏顺序。⼤部分操作符是左结合(从左向右执⾏),少数运算符是右结合(从右向左执⾏),⽐如赋值运算符( = )。

2. 例如表达式5 * 6 / 2里面 * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执⾏,先计算 5 * 6 , 再计算 6 / 2 。

3.  各操作符优先级和结合性的官方参考:C 运算符优先级 - cppreference.com

十、表达式求值

10.1 整型提升

1. 概念:C语⾔中整型算术运算总是⾄少以默认整型类型int的精度来进⾏运算的,为了获得这个精度,表达式中的字符和短整型操作数在使⽤之前会被转换为普通整型,这种转换称为整型提升。(注意:整型提升针对的是整型)

2. 整型提升的意义: 表达式的整型运算要在CPU的相应运算器件内执⾏,CPU内整型运算器的操作数的字节⻓度⼀般就是int的字节⻓度,同时也是CPU的通⽤寄存器的⻓度。 因此,即使两个char类型的相加,在CPU执⾏时实际上也要先转换为CPU内整型操作数的标准⻓度。 通⽤CPU是难以直接实现两个8⽐特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种⻓度可能⼩于int⻓度的整型值,都必须先转换为int或unsigned int,然后才能送⼊CPU去执⾏运算。

3. //实例1

    char a,b,c;

    ...

   a = b + c;

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

5. 如何进⾏整体提升呢?

    ① 有符号整数提升按照符号位来提升。

    ② ⽆符号整数提升,⾼位补0。

6. //负数的整形提升

    char c1 = -1;

    变量c1的⼆进制位(补码)中只有8个⽐特位:

    1111111

    因为 char 为有符号的 char

    所以整形提升的时候,⾼位补充符号位,即为1

    提升之后的结果是: 11111111 11111111 11111111 11111111

7. //正数的整形提升

    char c2 = 1;

    变量c2的⼆进制位(补码)中只有8个⽐特位:

    00000001

    因为 char 为有符号的 char

    所以整形提升的时候,⾼位补充符号位,即为0

    提升之后的结果是: 00000000 00000000 00000000 00000001

10.2 算数转换

1. 如果某个操作符的各个操作数属于不同的类型,那么除⾮其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就⽆法进⾏

2. 下⾯的层次体系称为寻常算术转换。

     long double

     double

     float

     unsigned long int

     long int

     unsigned int

     int

3. 如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算

十一、问题表达式

11.1 示例1

1. //表达式的求值部分由操作符的优先级决定

    //表达式1

  a*b + c*d + e*f

2. 表达式1在计算的时候,由于 * ⽐ + 的优先级⾼,只能保证, * 的计算是⽐ + 早,但是优先级并不能决定第三个 * ⽐第⼀个 + 早执⾏

3. 所以即使我们知道了优先级和结合性,也未必能准确得出表达式的计算顺序,它可能不具有唯一性,当表达式中的a、b、c、d、e、f不是单纯的数值而是表达式时,可想而知在不具有唯一性的表达式中,计算的结果可能是有所差异的。

4. 解决方法,不要写有连续几个操作符的表达式,把复杂的计算尽量拆开去写;或者在复杂的表达式中用()来明确表示哪个先算,哪个后算

11.2 示例2

1. //表达式2

    c + --c;

2. 上面的表达式中,操作符的优先级只能决定⾃减 -- 的运算在 + 的运算的前⾯,但是我们并没有办法得知, + 操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义的。(例如,c原本为5,--c后c为4,但我们无法判断,第一个c是将5带入表达式,还是将4带入表达式。如果要修改,可以写成c + (--c),这样写会默认+ 的左操作数的获取在右操作数之后。)

11.3 示例3

1. //表达式3

    int main()

    {

            int i = 10;

            i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i);

            return 0;

    }

2. 表达式3在不同编译器中测试结果:

3. 这个示例也说明了不同的编译器对复杂表达式的解读方式是有差异的。

11.4 示例4

#include <sdtio.h>
int fun()
{static int count = 1;return ++count;
}int main()
{int answer;answer = fun() - fun() * fun();printf( "%d\n", answer);//输出多少?return 0;
}

1. 虽然在⼤多数的编译器上求得结果都是相同的,但是上述代码 answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:先算乘法,再算减法。 函数的调⽤先后顺序⽆法通过操作符的优先级确定,answer = fun() - fun() * fun()可能是 2-3*4 也可能是 3-4*2 等。

11.5 总结 

1. 即使有了操作符的优先级和结合性,我们写出的表达式依然有可能不能通过操作符的属性确定唯⼀的计算路径,那这个表达式就是存在潜在⻛险的,建议不要写出特别负责的表达式。

本篇文章已完结,谢谢支持哟 ^^ !!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3032391.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

干货教程【AI篇】| 目前全球最强AI换脸工具swapface详细图文教程及整合包下载

需要这个工具整合包的小伙伴可以关注一下文章底部公众号&#xff0c;回复关键词【swapface】即可获取。 从我们的链接下载&#xff0c;得到这个exe文件 双击运行即可进入安装界面 如下图所示已经在安装中啦 安装好之后我们根据上面的安装路径找到要执行的文件 双击红框中的…

Doris【部署 01】Linux部署MPP数据库Doris稳定版(下载+安装+连接+测试)

本次安装测试的为稳定版2.0.8官方文档 https://doris.apache.org/zh-CN/docs/2.0/get-starting/quick-start 这个简短的指南将告诉你如何下载 Doris 最新稳定版本&#xff0c;在单节点上安装并运行它&#xff0c;包括创建数据库、数据表、导入数据及查询等。 Linux部署稳定版Do…

Excel-VBA报错01-解决方法

【已删除的部件:部件/xl/vbaProject.bin。(Visual Basic for Applications(VBA))】 1.问题复现&#xff1a; Win10 &#xff1b;64位 &#xff1b;Office Excel 2016 打开带有宏的Excel文件&#xff0c;报错&#xff1a;【已删除的部件&#xff1a;部件/xl/vbaProject.bin。…

MFC DLL注入失败一些错误总结

使用cheat Engine为MFC窗口程序注入DLL时一定要注意&#xff0c;被注入的exe程序和注入的DLL 的绝对路径中一定不要带有中文字符&#xff0c;否则会遇到各种各样的奇怪错误&#xff0c;如下所示&#xff1a; 以下是dll绝对路径中均含有中文字符&#xff0c;会报错误&#xff…

一种简单的小报表本地缓存方案

适应如下场景&#xff1a;关联表多&#xff0c;接口响应慢&#xff0c;报表数据不多&#xff0c;可能就十多行。参数也固定&#xff0c;实时性要求不高&#xff0c;隔那么半小时刷新一次&#xff0c;查询性能要求高&#xff0c;给领导看的&#xff0c;要求很快。 使用示例&…

【桌面应用开发】Rust+Tauri框架项目打包操作

1.项目npm install下载项目依赖&#xff08;需要配置好node.js环境&#xff09; 可参考&#xff1a;https://blog.csdn.net/m0_64346565/article/details/138319651 2.自定义图标&#xff08;项目初始化开始第一次需要配置生成&#xff0c;后面可跳过这一步骤&#xff09; Ta…

ITIL4视角下的IT监控与故障管理:守护服务健康的双刃剑

引言&#xff1a;监控的曙光 在IT服务管理的浩瀚星图中&#xff0c;"监控"这一璀璨星辰终于得到了应有的重视与聚焦。ITIL4的出台&#xff0c;不仅明确将监控告警纳入事件管理的广阔宇宙&#xff0c;而且强调了其在预防故障、保障服务连续性中的核心地位。当组织拥抱…

k8s设置在任意node里执行kubectl 命令

一、问题 正常来讲kubectl 只能在master node 里运行 当我们尝试在某个 node 节点来执行时&#xff0c; 通常会遇到下面错误 执行错误&#xff1a;The connection to the server localhost:8080 was refused - did you specify the 原因&#xff1a;因为k8s的各个组建&#xf…

Oracle 多表查询

关联查询 一、sql:1992语法的连接笛卡尔积等值连接非等值连接自连接外连接 二、sql:1999语法的连接交叉连接自然连接USING创建连接ON创建连接左外连接右外连接FULL OUTER JOININNER JOIN 三、子查询子查询的种类单行子查询多行子查询 在From字句中使用子查询练习 四、行转列 一…

小兴教你做平衡小车-平衡车主板绘制(V4版本 b站课程所使用版本)

文章目录 1 原理图总览2 原理图各模块细致图2.1 2.54mm插针(stm32最小系统扩展接口)2.2 OLED显示2.3 MPU60502.4 TB6612驱动电路2.5 2.54mm排座(stm32最小系统连接接口)2.6 测距模块2.7 蓝牙模块2.8 蜂鸣器模块2.9 电池电压检测电路2.10 M3固定孔2.11 用户小灯模块2.12 电源接口…

在go-zero中使用jwt

gozero使用jwt 两个步骤 获取token验证token 前端获取token 先编写 jwt.api 文件&#xff0c;放在api目录下 syntax "v1"info (title: "type title here"desc: "type desc here"author: "type author here"email: &quo…

无限集中的最小数字

题目链接 无限集中的最小数字 题目描述 注意点 1 < num < 1000 解答思路 由题意得&#xff0c;可以理解为最初集合中有1~1000之间的所有数字&#xff0c;如果集合中存在数字&#xff0c;则添加时不会有任何操作&#xff1b;在移除集合中的元素时&#xff0c;会按顺序…

记录使用极空间NAS通过Docker部署小皮面板(PhpStydy)运行 八图片当面付支付宝接口 PHP项目的遭遇

事件的起因还得从我用八图片的图片加密支付跳转功能&#xff0c;实现打赏金额发案例源码下载链接挣个烟钱的事。八图片的支付接口是PHP web项目的。正好我有个极空间的NAS&#xff0c;搭建到NAS上省去了买主机的费用。 导读 八图片是什么&#xff1f;极空间NAS 部署 PHP网站安装…

Go实现树莓派读取at24c02 eeprom读写数据

步骤 启用i2c 参考 Go实现树莓派读取bh1750光照强度 代码 package mainimport ("fmt""periph.io/x/conn/v3/i2c" )type AT24C02Device struct {dev *i2c.Dev }func NewAT24C02Device(addr uint16, bus i2c.BusCloser) (*AT24C02Device, error) {var (d…

图像融合-下游任务(目标检测、实例分割、深度估计)

下游任务: 采用目标检测、实例分割和深度估计的下游任务来验证图像融合结果质量。 文章目录 下游任务:1.目标检测2.实例分割3.深度估计Update1.目标检测 YOLOv8:https://github.com/ultralytics/ultralytics 步骤内容第一步下载项目到本地第二步安装README中项目相关的环…

LibreNMS简介

目录 1 LibreNMS简单介绍1.1 LibreNMS介绍 2 安装2.1 Ubuntu安装1、安装依赖2、添加 librenms 用户3、下载 LibreNMS4、设置权限5、安装 PHP 依赖项6、设置时区7、配置 MariaDB8、配置 PHP-FPM9、配置 Web 服务器10、启用 lnms 命令11、配置 snmpd12、cron13、启用调度程序14、…

mysql NDBcluster数据库集群介绍、部署及配置

前言: MySQL集群是一个无共享的、分布式节点架构的存储方案,旨在提供容错性和高性能。它由三个主要节点组成:管理节点(MGM)、数据节点和SQL节点。 管理节点(MGM) 定义与用途:管理节点是MySQL Cluster的控制中心,负责管理集群内的其他节点。它提供配置数据,启动和停止…

Flask gevent启动报错UnicodeDecodeError

文章目录 环境代码报错Track解决思路 环境 acondana 24.1.2python 3.7.13 32bitflask 2.2.3gevent 21.8.0 代码 port 7236 logging.basicConfig(levellogging.INFO, # 控制台打印的日志级别filename./logs/app.log, # 将日志写入log_new.log文件中filemodea, # 模式&…

【4】STM32·FreeRTOS·中断管理

目录 一、什么是中断 二、中断优先级分组设置 2.1、中断优先级基本概念 2.2、中断优先级分组 2.3、FreeRTOS中断特点 三、中断相关寄存器 3.1、系统中断优先级配置寄存器 3.2、PendSV和Systick中断优先级的配置 3.3、中断屏蔽寄存器 四、FreeRTOS中断管理实验 一、什…

阿里云服务器在线安装nginx

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《nginx实战》 目录 内容简介 安装步骤 1.root用户登录连接阿里云服务器 2.在usr/local下新建nginx目录 3.安装 1安装下载工具 2下载nginx压缩包 3解压 4安装nginx依赖的库 5编译并安装 6启动nginx 7开启…