IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [C++]踩坑日记:内存别名 -> 正文阅读

[C++知识库][C++]踩坑日记:内存别名

内存别名:指的是引用同一处地址的多个不同指针变量。

1. 常规的变量交换方式如下:

void swap(int *a, int* b){
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

不使用临时变量的两种交换方式:

void swap_xor(int *a, int* b){ // 异或方式
	*a = *a ^ *b;
	*b = *a ^ *b;
	*a = *b ^ *a;
}
void swap_add(int *a, int* b){ // 求和方式
	*a = *a + *b;
	*b = *a - *b;
	*a = *a ^ *b;
}

这两种方式并不高端,不但增加了代码阅读难度同时可能产生某些问题,如下。

int main() {
    int num1 = 1, num2 = 2;
	
	swap(&num1, &num2); 
	cout<<"num1="<<num1<<", num2="<<num2<<endl; // 2,1
	swap_xor(&num1, &num2);
	cout<<"num1="<<num1<<", num2="<<num2<<endl;// 1,2
	swap_add(&num1, &num2);
	cout<<"num1="<<num1<<", num2="<<num2<<endl;// 2,1

	swap(&num1, &num1); 
	cout<<"num1="<<num1<<", num2="<<num2<<endl; // 2,1 原值交换,保持不变
	swap_xor(&num1, &num1);
	cout<<"num1="<<num1<<", num2="<<num2<<endl;// 0,2 原值改变
	swap_add(&num1, &num1);
	cout<<"num1="<<num1<<", num2="<<num2<<endl;// 0,1 原值改变
}

原因推导(前提a==b)

void swap_xor(int* a, int* b) {
   *a = *a ^ *b;  // => *a = *b = *a ^ *b = 0
   *b = *a ^ *b;  // => *a = *b = *a ^ *b = 0
   *a = *a ^ *b;  // => *a = *b = *a ^ *b = 0
}
void swap_add(int* a, int* b) {
   *a = *a + *b; // => *a = *b = *a + *b = 2 * *a
   *b = *a - *b; // => *a = *b = *a - *b = *a - *a = 0
   *a = *a - *b; // => *a = *b = *a - *b = 0 
}

2. 类似的情况,数组求和

一般的数组求和方式都会像下面这么写,但是编译器无法进行优化,每次不但要读取arr内存地址,还要从target内存地址读取和写入。

void sum(int* arr, int length, int* target){
	for(int i = 0; i < length; i++){
		*target += arr[i];
	}
}

优化方式:局部变量临时存储。这样编译器会将结果暂存到寄存器中,因为res变量可以放到寄存器中,每次只需要读取arr内存地址即可。

void sum_advance(int* arr, int length, int* target){
	int res = *target;
	for(int i = 0; i < length; i++){
		res += arr[i];
	}
	*target = res;
}

引发问题:当arr和target地址一致的时候,内存别名引发问题。
这也是第一种方法哪怕编译器加上优化参数-O1也不可能将结果暂存寄存器的,因为会造成与程序逻辑不符,虽然符合编程意图。

int main() {
    int arr[5] = {1,2,3,4,5};
	int* target = arr+2;
	sum_advance(arr,5,target); // 18,期望15
	cout<< *target <<endl;
}

c99中引入了restrict关键字,表明能够更改指针指向内容的只有该变量一个。那么sum函数将可以得到优化,本身在循环体里面target就没有进行写入,同时restrict保证了只能target写入,那么加上-O1参数可以得到优化。

void sum(int* restrict arr, int length, int* restrict target){
	for(int i = 0; i < length; i++){
		*target += arr[i];
	}
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:03:43  更:2021-09-29 10:05:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/8 4:42:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码