15.75.【C语言】表达式求值

目录

一.整型提升

1.定义

2.

一.整型提升

1.定义

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

2.整型提升的原因:

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

char a;//char本质上是存储的是ASCII值 
short b;

char,short-->int 或 unsigned int

3.方法:

*有符号整数提按照变量的数据类型的符号位来提升至int的位数

char a;-->signed char a;

+5原码=反码=补码=00000000 00000000 00000000 00000101 (作int时)(从8bit-->32bit)

由于char只能存8 bit,所以变量里存储00000000 00000000 00000000 00000101,称为整型截断:一个字节大的整型数据赋值给一个字节小的整型变量时,发生的数据丢失

*无符号整数提升,高位补0至int的位数

 练习:求打印的值

#include <stdio.h>
int main()
{char a=5;char b=126;char c=a+b;printf("%d",c);
}

分析:计算(a+b)前char整型提升至int

5:      0000000 00000000 00000000 00000101

126:    00000000 00000000 00000000 01111110

5+126: 00000000 00000000 0000000 10000011

存储至c时,整型截断:00000000 00000000 0000000 100000011

所以c的二进制序列为100000011,c的十进制序列为131,但打印的结果不是131

要充分理解:字符和短整型操作数使用之前被转换为普通整型的含义,printf也算使用!

解释1:

VS2022中char默认按signed char处理,最高位是1,所以高位补1

补码:11111111 11111111 11111111 10000011

符号位不变,其余各位取反再+1:10000000 00000000 00000000 01111101-->-125

解释2:“环绕溢出”

由于8bit存储有符号整数范围-128~+127

所以画图:


练习:代码修改后求打印的值

#include <stdio.h>
int main()
{unsigned char a = 5;unsigned char b = 126;unsigned char c = a + b;printf("%d", c);
}

分析指定无符号(unsigned char)整数,范围是0~2的8次方-1即255,显然131<255,所以打印131

二.算术转换

1.定义

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行

2.剖析

float a;
double b;
a+b;

a+b,a是float,b是double,两者类型不一样,VS会把float转换为double,执行a+b;具体原因参见第3点

3.寻常算术转换

1. long double
2. double
3. float
4. unsigned long int
5. long int
6. unsigned int
7. int

规则:序号大的转换为序号小的

序号3是float,序号2是double,2<3,所以把float转换为double

4.问题表达式例子分析

表达式的执行看优先级(回顾15.25【C语言】操作符的属性),而且表达式真正计算的时候先看相邻操作符的优先级再决定先算谁,但有了优先级就一定能确定唯一的运算顺序吗?

a*b + c*d + e*f

执行顺序有两种可能:

1.先算完*,后算完+

2.a*b-->c*d-->a*b + c*d-->e*f-->a*b + c*d + e*f

显然不能确定唯一的运算顺序

注意:不同的运算顺序可能答案有所不同,上述a,b,c,d,e,f可以是变量,也可以是表达式


int c=3;
int b=c + --c;

查优先级可知,先--后+ ,但+号两边都含c,+的左操作数在--c之前还是之后准备好的,无从得知,建议再设一个变量


出自《C和指针》

int main()
{int i = 10;i = i-- - --i * ( i = -3 ) * i++ + ++i;printf("i = %d\n", i);return 0;
}

理由和上方解释思想一样 ,不同编译器解释出来的答案不一样


下列代码的输出结果是否可求?

#include <stdio.h>
int fun()
{static int count = 1;return ++count;
}int main()
{int answer=0;answer = fun() - fun() * fun();printf( "%d\n", answer);return 0;
}

注意到 static int 回顾17.【C语言】初识常见关键字 下

摘取:

int a=1;等价于auto int a=1;

static int a=1;修饰局部变量,a不会自动销毁,生命周期变长

总结:static修饰局部变量时改变了变量的存储类型,进而改变了局部变量的生命周期

count会从1到4而且函数的调用先后顺序无法通过操作符的优先级确定


#include <stdio.h>
int main()
{int i = 1;int result = (++i) + (++i) + (++i);printf("%d\n", result);printf("%d\n", i);return 0;
}

Debug x86环境下编译 ,反汇编

#include <stdio.h>
int main()
{
006B1870  push        ebp  
006B1871  mov         ebp,esp  
006B1873  sub         esp,0D8h  
006B1879  push        ebx  
006B187A  push        esi  
006B187B  push        edi  
006B187C  lea         edi,[ebp-18h]  
006B187F  mov         ecx,6  
006B1884  mov         eax,0CCCCCCCCh  
006B1889  rep stos    dword ptr es:[edi]  
006B188B  mov         ecx,offset _2D923C74_FileName@c (06BC008h)  
006B1890  call        @__CheckForDebuggerJustMyCode@4 (06B132Ah)  
006B1895  nop  int i = 1;
006B1896  mov         dword ptr [i],1  int result = (++i) + (++i) + (++i);
006B189D  mov         eax,dword ptr [i]  
006B18A0  add         eax,1  
006B18A3  mov         dword ptr [i],eax  
006B18A6  mov         ecx,dword ptr [i]  
006B18A9  add         ecx,1  
006B18AC  mov         dword ptr [i],ecx  
006B18AF  mov         edx,dword ptr [i]  
006B18B2  add         edx,1  
006B18B5  mov         dword ptr [i],edx  
006B18B8  mov         eax,dword ptr [i]  
006B18BB  add         eax,dword ptr [i]  
006B18BE  add         eax,dword ptr [i]  
006B18C1  mov         dword ptr [result],eax  printf("%d\n", result);
006B18C4  mov         eax,dword ptr [result]  
006B18C7  push        eax  
006B18C8  push        offset string "%d\n" (06B7B30h)  
006B18CD  call        _printf (06B10D2h)  
006B18D2  add         esp,8  printf("%d\n", i);
006B18D5  mov         eax,dword ptr [i]  
006B18D8  push        eax  
006B18D9  push        offset string "%d\n" (06B7B30h)  
006B18DE  call        _printf (06B10D2h)  
006B18E3  add         esp,8  return 0;
006B18E6  xor         eax,eax  
}
006B18E8  pop         edi  
006B18E9  pop         esi  
006B18EA  pop         ebx  
006B18EB  add         esp,0D8h  
006B18F1  cmp         ebp,esp  
006B18F3  call        __RTC_CheckEsp (06B124Eh)  
006B18F8  mov         esp,ebp  
006B18FA  pop         ebp  
006B18FB  ret  

int i = 1;以上的汇编指令是栈区的初始化,具体分析见36.【C语言】函数栈帧的创建和销毁

重点分析int i=1;和int result这行代码

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

njs、nginx JavaScript、在nginx上写JavaScript、nginx支持js

njs、nginx JavaScript、在nginx上写JavaScript、nginx支持js 现在是 2024-08-05 &#xff0c;在一个月前&#xff0c;我逛nginx官网&#xff0c;还没有这个模块的介绍。看njs官网&#xff0c;在四年前已经创建这个项目。不知道是不是近期才把这个项目纳入。以前不知道这模块&…

C# 构建观测者模式(或者为订阅者模型)

前言&#xff1a; 观测者模型的基本理念&#xff0c;就是&#xff0c;我有一个公共的事件&#xff0c;定义好他的事件的触发、数据接口。然后&#xff0c;通过增加订阅者&#xff08;实例&#xff09;来订阅这个事件的&#xff0c;或者说观察这个事件。如果事件发生&#xff0…

未授权访问漏洞系列详解⑥!

JBoss未授权访问漏洞 JBoss是一个基于J2EE的开放源代码应用服务器&#xff0c;代码遵循LGPL许可&#xff0c;可以在任何商业应用中免费使用;JBoss也是一个管理EJB的容器和服务器&#xff0c;支持EJB1.1、EJB 2.0和EJB3规范。,默认情况下访问 http://ip:8080/jmx-console 就可以…

【Java数据结构】---初始数据结构

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 前言 从今天开始我们就要学习Java…

Altium designer学习笔记03 -原理图绘制

原理图绘制 1. 原理图页大小设置2.原理图格点的设置3. 原理图模板的应用4. 元件的放置5.元件属性的编辑6.元件的选择、移动、旋转、镜像6.1 元件的选择6.2 元件的移动6.3 元件的旋转6.3 元件的镜像 7.元件的复制/剪切/粘贴8.元件的排列与对齐9.绘制导线的导线属性设置10.放置网…

实时数仓分层架构详解

首先&#xff0c;我们从数据仓库说起。 数据仓库的概念可以追溯到20世纪80年代&#xff0c;当时IBM的研究人员提出了商业数据仓库的概念。数据仓库概念的提出&#xff0c;是为了解决和数据流相关的各种问题&#xff0c;特别是多重数据复制带来的高成本问题。 数据仓库之父Bill …

简单反射型XSS的复现

xss反射型攻击&#xff1a; 1.最简单的漏洞复现&#xff1a; 这里我们有一个最简单的网页&#xff1a;由于地址不存在&#xff0c;所以图片加载不出来。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta…

skynet 连接redis

文章目录 概述main.luaagent.luaredis.lua 小结 概述 之前写过skynet 入门篇&#xff0c;还有skynet实操篇&#xff1b;这2篇&#xff0c;主要写了skynet如何使用&#xff0c;还有些skynet的调用流程之类。 其实&#xff0c;看过skynet的demo之后&#xff0c;发现skynet中没有…

Simulink模型开发中的一些自动化方法

随着Simulink模型的产品化开发进程&#xff0c;许多模型开发人员会关心模型的建模自动化问题。比如如何对模型中的元素进行批量查找和修改&#xff1b;如何构建自己的建模规则对模型进行检查&#xff1b;如何实现测试自动化等。在这些使用场景中我们都需要了解一些Simulink函数…

谈谈冯诺依曼体系

我们都知道冯诺依曼体系这张图最为代表性&#xff0c;而接下来我们就来浅谈一下各部分之间的作用~ 输入设备&#xff1a;键盘&#xff0c;磁盘&#xff0c;网卡&#xff0c;话筒等等 输出设备&#xff1a;磁盘&#xff0c;网卡&#xff0c;声卡&#xff0c;显示屏等等 这些硬件…

1.1、centos stream 9安装Kubernetes v1.30集群 环境说明

最近正在学习kubernetes&#xff0c;买了一套《Kubernetes权威指南 从Docker到Kubernetes实践全接触(第六版)》这本书讲得很好&#xff0c;上下两册&#xff0c;书中k8s的版本是V1.29&#xff0c;目前官网最新版本是v1.30。强烈建议大家买一套看看。 Kubernetes官网地址&#x…

sql注入——二次注入

二次注入 简介工具环境具体实施 简介 二次注入是一种较为隐蔽的 SQL 注入攻击方式。它并非直接在输入时进行攻击&#xff0c;而是先将恶意数据存储到数据库中&#xff0c;这些数据看似正常。随后&#xff0c;应用程序在后续的操作中&#xff0c;再次使用或处理这些之前存储的恶…

消息队列:Kafka吞吐量为什么比RocketMQ大

根据资料显示RocketMQ每秒能处理10W量级数据&#xff0c;而Kafka能处理17W量级数据。 这两者差别主要再使用的零拷贝技术不一样。 再什么情况下零拷贝技术诞生了 为了防止消息队列中的消息因为各种意外情况丢失&#xff0c;要对消息进行持久化处理&#xff0c;将其存储在磁盘…

NLP——文本预处理

本文思维导图 文本预处理及其作用 文本语料在输送给模型前一般需要一系列的预处理工作, 才能符合模型输入的要求, 如: 将文本转化成模型需要的张量, 规范张量的尺寸等, 而且科学的文本预处理环节还将有效指导模型超参数的选择, 提升模型的评估指标. 一、文本处理的基本方法 1…

C++ | Leetcode C++题解之第326题3的幂

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isPowerOfThree(int n) {return n > 0 && 1162261467 % n 0;} };

【TS】declare 全局声明方式

declare关键字 declare是描述TS文件之外信息的一种机制&#xff0c;它的作用是告诉TS某个类型或变量已经存在&#xff0c;我们可以使用它声明全局变量、函数、类、接口、类型别名、类的属性或方法以及后面会介绍的模块与命名空间。 declare关键字用来告诉编译器&#xff0c;某…

工业控制常用的EtherNet/IP、OPC UA协议的标签数据转发到另外的PLC寄存器地址

在工业自动化领域&#xff0c;越来越多的碰到标签方式通讯的设备&#xff0c;常用有CIP(基于EtherNet/IP) 的协议、OPCUA协议等&#xff0c;CIP协议主要是罗克韦尔/AB的PLC、欧姆龙NX/NJ系列的PLC等&#xff0c;OPCUA协议常见于工业机器人、智能焊接设备等。在不具备标签协议接…

C语言 ——深入理解指针(2)

目录 1. 数组名的理解2. 二级指针3. 指针数组4. 字符指针变量5. 数组指针变量6. 函数指针变量7. 函数指针数组 1. 数组名的理解 这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址&#x…

普华-PowerPMS APPGetUser SQL注入致RCE漏洞复现

0x01 产品简介 PowerPMS是上海普华科技自主研发的移动端工程项目管理产品。支持中英文切换,可与普华PowerOn、PowerPiP系列产品配套使用。产品与工程项目为核心,为项目各参建方提供包括任务管理、文档管理、质量检查、安全检查、施工日志、进度反馈、即时消息等功能在内的服…

Rust 所有权

所有权 Rust的核心特性就是所有权所有程序在运行时都必须管理他们使用计算机内存的方式 有些语言有垃圾收集机制&#xff0c;在程序运行时&#xff0c;他们会不断地寻找不再使用的内存在其他语言中&#xff0c;程序员必须显式的分配和释放内存 Rust采用了第三种方式&#xff1…