当前位置: 首页 > news >正文

临平房产做网站的公司wordpress屏蔽功能org

临平房产做网站的公司,wordpress屏蔽功能org,最新73种暴利产品竞价单页网站制作带订单后台系统模板,北京企业信息查询官网1. 认识 volatile 1.1 volatile 的作用 每次都从内存中读取该值,而不会因编译器优化从缓存的地方读取(如寄存器中,由于访问寄存器的速度比 RAM 快),从而保证 volatile 变量被正确读取。 问题示例:从寄存器中…

1. 认识 volatile

1.1 volatile 的作用

每次都从内存中读取该值,而不会因编译器优化从缓存的地方读取(如寄存器中,由于访问寄存器的速度比 RAM 快),从而保证 volatile 变量被正确读取。

  • 问题示例:从寄存器中读取值,被修改的变量值不能及时得到反应。
#include <iostream>
using namespace std;int main() {int i = 10;int a = i;cout << a << endl;_asm {mov dword ptr[ebp - 4], 80}int b = i;cout << b << endl;return 0;
}

VS 2022 环境下生成 x86 Release 版本(Release 模式下才会对程序代码进行优化),输出结果如下,可见 i 的值还是 10,并没有变成 80。
在这里插入图片描述

  • 解决方法:volatile

VS 2022 环境下生成 x86 Release 版本,用 volatile 定义变量 i, 输出结果如下。
在这里插入图片描述

1.2 volatile 的应用场景

1.2.1 并行设备的硬件寄存器

假如要初始化一个设备,这个设备的某个寄存器为 0xff800000:

int* output = (unsigned int*)0xff800000;int init() {for (int i = 0; i < 10; i++) {*output = i;}
}

编译器经过优化后认为前面的循环是无用的,对最后的结果毫无影响,因为最终是将 output 这个指针的内容赋值为 9,所以最后编译器编译的代码结果相当于:

int init() {*output = 9;
}

但如果对此设备进行初始化的过程必须像开头一样顺序地对其赋值,则优化过程显然不行。需要加 volatile。

1.2.2 一个中断服务子程序中会访问到的变量

static int i = 0;int main() {while (1) {if (i) {dosomething();}}
}// 中断服务程序
void IRS() {i = 1;
}

代码本意是产生中断时,IRS 响应,i 被置为 1,然后 main 中 dosomething()。但是,编译器判断在 main 中没有动过 i,因此可能只执行一次把 i 读到寄存器的操作,然后 if 判断时都只用这个寄存器里的值,导致 dosomething 永远无法执行。

1.2.3 多线程应用中被几个任务共享的变量

volatile bool bStop = false;void threadFunc1() {while (!bStop) {......}
}void theadFunc2() {bStop = true;
}

如果没有 volatile 修饰,threadFunc1 中将是个死循环,因为 bStop 已经被读到寄存器中。

1.3 volatile 的常见问题

1.3.1 一个参数既可以是 const 也可以是 volatile 吗?为什么?

YES!例如只读的状态寄存器。

1.3.2 一个指针可以是 volatile 吗?为什么?

YES!例如:这里需要注意两点:

  1. volatile int *p; p 是指向 volatile int 的普通指针,*p = 10; 每次访问都会真正读写内存,因为 *p 的内容可能随时被硬件或其他线程修改,所以不能优化。
  2. int * volatile p; p 是一个 volatile 指针,指针变量本身可能随时被外部改变(例如通过 DMA、硬件寄存器映射)
  3. 还有 volatile int * volatile p;

1.3.3 下面的函数有什么错误?

int square(volatile int* ptr) {return *ptr * *ptr;
}

因为加了 volatile,所以上述代码变成下面:

int square(volatile int* ptr) {int a, b;a = *ptr;b = *ptr;return a * b;
}

由于 *ptr 可能被改变,所以 a 和 b 可能不相同,导致代码不符合预期。可以修改为如下:

int square(volatile int* ptr) {int a;a = *ptrreturn a * a;
}

2. 数组与指针详解

2.1 数组

2.1.1 数组名

数组名,本质是一个文字常量(指针常量),代表第一个元素的地址和数组的首地址。数组名本身不可寻址(理解为不能类似自增这种操作,改变其值,也呼应了这句开头的文字常量)。

int a[10];int* &r = a; // 错误
int* const &r = a; // 正确

2.1.2 数组类型

  • 对于一个整型变量,其类型是 int。那么对于数组 a,它的类型是怎样的?其类型有两部分,一个是元素类型,一个是元素个数。所以对于 sizeof 来说,能够计算出来占用的空间大小就是数组类型的大小,也即 元素个数 乘上 元素类型的大小。
  • 对于数组 a 来说,a、&a[0]、a+0 是等价的。

2.1.3 数组的引用

  • 对于数组 a,在数据区开辟一个无名临时变量,将数组 a 的地址常量复制到该变量中,再将常引用 r 与此变量进行绑定。即先有 int *,表示复制数组 a 的地址,然后是一个常引用 const &。
  • 另一种就比较直观了,直接数组类型 int [4],然后用一个引用 &。
int a[4];int* const &r = a;
int (&ra)[4] = a;

2.1.4 数组指针

数组指针,数组 a 和 &a 的类型是不一样的,a 的类型就是数组类型 int[4],在表达式中退化为 int*;而 &a 是取数组的地址,也即它的类型是 int(*)[4],所以 a+1 表示第 2 个元素的地址,而 &a + 1 是跳过一个数组大小的地址。示例如下:

#include <iostream>
using namespace std;int main()
{int a[4] = {};int* const &r = a;int (&ra)[4] = a;cout << a << endl;cout << &a << endl;cout << a+1 << endl;cout << &a+1 << endl;return 0;
}
$ g++ test.cpp
$ ./a.out
0x7ffe02deeeb0
0x7ffe02deeeb0
0x7ffe02deeeb4
0x7ffe02deeec0

2.2 指针

任何指针类型所占用的空间一般都是 4 字节(在 32 位平台上)。比如 sizeof(int*),sizeof(float*),等等。
野指针:指向非法内存地址的指针

2.2.1 使用未初始化的指针

int *p;
cout << *p << endl;

2.2.2 指针所指向的对象已经消亡

#include <iostream>
using namespace std;int* retAddr() {int num = 10;   // 局部变量,存放在栈上return &num;    // ❌ 返回局部变量的地址
}int main() {int* p = NULL;p = retAddr();          // p 接收了一个已经无效的地址cout << &p << endl;     // 打印 p 这个指针变量自己的地址cout << *p << endl;     // ❌ 解引用一个悬空指针,未定义行为
}

2.2.3 指针释放之后未置空

#include <iostream>
using namespace std;int main() {int* p = NULL;p = new int[10];     // 在堆上分配一个大小为 10 的 int 数组delete p;            // ❌ 错误释放方式cout << "p[0]:" << p[0] << endl;  // ❌ 使用已释放的内存
}

2.2.4 realloc() 函数使用不当

#include <malloc.h>void main() {char *p, *q;p = (char *)malloc(10);q = p;p = (char *)realloc(p,20);// ...
}
  1. p = malloc(10)
    向堆申请 10 字节内存,返回首地址赋给 p。此时 q = p,所以 qp 指向同一块 10 字节内存。
  2. p = realloc(p, 20)
    试图把 p 指向的内存扩展到 20 字节。
    如果原地址后面刚好有足够空闲空间realloc 会直接在原地扩展,返回的地址和 p 相同,q 依然有效。
    如果原地址后面没有足够空间realloc 会:
    • 在堆中找一块新的 20 字节内存(相当于 malloc(20)),
    • 把原来 10 字节的数据拷贝到新内存,
    • 释放原来的 10 字节内存,
    • 返回新内存的地址。
    • 此时 p 被更新为新地址,但 q 依旧保存着旧地址——而旧内存已经被释放。
  3. 所以 q 成为了 悬空指针(dangling pointer)
    如果再用 q 访问数据,就会导致 未定义行为,可能导致崩溃或数据错误。
  • 正确的写法:如果真的要保留旧数据的引用,就要明确判断 realloc 的返回值,并避免让 q 成为野指针。例如:
char *p, *q;
p = malloc(10);
q = p;char *tmp = realloc(p, 20);
if (tmp != NULL) {p = tmp;// q 现在不能再安全使用旧地址q = p;   // 如果还要 q 继续指向新地址,就必须更新
} else {// realloc 失败,p 仍然指向原来的 10 字节
}

3. 文字常量和常变量

3.1 文字常量

文字常量:编译后写在代码区,不可寻址不可更改。包括 数值常量,字符常量和符号常量。

int &r = 5; // ❌ 错误

因为数值常量没办法寻址。但下面的却是可以的,编译器将数值常量转变为了常变量,在数据区开辟了一个值为 5 的无名整型常变量,然后引用绑定。

const int &r = 5;

3.2 常变量

常变量:定义时必须显式初始化且值不可修改的变量。可以寻址。例如 字符串常量。
全局常变量存储在只读存储区,不可修改;局部常变量存储在栈上,可以间接修改。

http://www.dtcms.com/a/461221.html

相关文章:

  • Skywalking 的本地开发配置
  • iOS 上架 App 全流程实战,应用打包、ipa 上传、App Store 审核与工具组合最佳实践
  • JavaScript核心构成与基础语法详解2
  • 邹平网站建设公司淘宝网站开始怎么做
  • fs 文件系统:Node.js 操作磁盘的 “万能工具”
  • Android + iOS 手机抓包 App 实操教程
  • 智慧新零售时代:施易德系统平衡技术与人力,赋能门店运营
  • 标准编码与算法
  • Python获取变量名本身​​——varname库
  • 专业站全返利网站建设
  • 网站设计提案安阳市建设工程领域网站
  • 鸿蒙(OpenHarmony)声明式 UI 开发入门:从「智慧校园」项目学基础语法
  • js移动开发框架
  • 【腾讯拥抱开源】Youtu-Embedding:基于CoDiEmb的一个协作而独特的框架,用于信息检索与语义文本相似性中的统一表征学习
  • 西蔵自治区建设厅网站wordpress防盗链插件
  • VSCode中使用conda activate 虚拟环境,没报错,但没进入环境
  • vue修改element-ui的默认的class
  • ModuleNotFoundError: No module named ‘UI_xiangmu‘
  • 网站建设方案及报价霍州做网站
  • mybatis-generator插件自动生成mapper及其实体模型配置
  • 计算机毕业设计 基于k-means的校园美食推荐系统 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
  • 【代码大模型-后门安全】Backdoors in Neural Models of Source Code
  • javaweb后端优雅处理枚举
  • 帝国cms小程序搞起来简直好用的不行
  • 高效批量调整图像尺寸的方案
  • 单片机供电处3.3V大电容导致程序可进调试但是无法暂停到具体语句
  • Java 实战:为 Word 文档中的文本与段落添加边框
  • 创业网站怎么做网站建设与网页设计...
  • git大文件储存机制是什么-为什么有大文件会出错并且处理大文件非常麻烦-优雅草卓伊凡
  • 机器学习之规则学习(Rule Learning)