先上一段代码
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
const int i(0);
int *j = (int *)&i;
cout<<j<<endl;
cout<<&i<<endl;
(*j)++;
printf("%d\n%d\n",*j,i);
return 0;
}
输出
0018FF44
0018FF44
1
0
Press any key to continue
问题来了,问什么看起来是j指向i,但是,i 与 *j 不同值呢?
起初,笔者认为是由于 printf 从右往左灌入导致的。
(*j)++
之后,*j不变,一次输出之后,*j 自增,就导致了上述输出。其实不然,代码如下
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
const int i(0);
int *j = (int *)&i;
cout<<j<<endl;
cout<<&i<<endl;
(*j)++;
(*j)++;
printf("%d\n%d\n",*j,i);
cout<<j<<endl;
cout<<&i<<endl;
return 0;
}
输出
0018FF44
0018FF44
2
0
仔细观察代码,感觉问题不在 printf。再次对代码修改
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
int i(0);
int *j = (int *)&i;
cout<<j<<endl;
cout<<&i<<endl;
(*j)++;
(*j)++;
printf("%d\n%d\n",*j,i);
cout<<j<<endl;
cout<<&i<<endl;
return 0;
}
输出
0018FF44
0018FF44
2
0
0018FF44
0018FF44
Press any key to continue
原因在于,编译器对指针做了优化。
如果是 const 变量,编译器会将其视作宏替换,不管地址什么的瞎变,它就是原来的值,即 i 恒等于 0;
如果是 j ,通常是会认为 i 在常量区,j 在栈区,指向常量区,i j 两者“地址”相同,这也没有错。
但是,有些编译器会对此做优化,显示是在同一内存地址,但是,乱七八糟变的时候就只会对 j 有效了,对 i 变换就会报错。
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
const int i(0);
int *j = (int *)&i;
cout<<j<<endl;
cout<<&i<<endl;
// i++; // 报错
printf("%d\n%d\n",*j,i);
cout<<j<<endl;
cout<<&i<<endl;
return 0;
}