内存别名:指的是引用同一处地址的多个不同指针变量。
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;
swap_xor(&num1, &num2);
cout<<"num1="<<num1<<", num2="<<num2<<endl;
swap_add(&num1, &num2);
cout<<"num1="<<num1<<", num2="<<num2<<endl;
swap(&num1, &num1);
cout<<"num1="<<num1<<", num2="<<num2<<endl;
swap_xor(&num1, &num1);
cout<<"num1="<<num1<<", num2="<<num2<<endl;
swap_add(&num1, &num1);
cout<<"num1="<<num1<<", num2="<<num2<<endl;
}
原因推导(前提a==b)
void swap_xor(int* a, int* b) {
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void swap_add(int* a, int* b) {
*a = *a + *b;
*b = *a - *b;
*a = *a - *b;
}
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);
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];
}
}
|