获取二级指针最后一个字节地址的实现问题及指针类型转换的疑问
我完全懂你现在的困惑——为啥直接对二级指针做算术运算得到的结果完全不对,转换成char*之后就正常了?这核心是C++里指针算术的规则在搞事情,咱们一步步掰扯明白:
先搞懂指针算术的本质
指针加减整数的时候,偏移的字节数不是你写的那个整数本身,而是 整数 × 指针指向类型的大小。举两个例子:
- 如果你有个
int* p,p+1会偏移sizeof(int)字节(通常是4或8),而不是1字节; - 同理,你的
int** ppq是二级指针,它指向的是int*类型的变量,所以ppq+1会偏移sizeof(int*)字节(64位系统下是8字节)。
分析你的两段代码
第二段错误代码的问题出在哪?
咱们看这段代码:
std::cout << ppq + sizeof(ppq) - 1 << std::endl;
在64位系统里,sizeof(ppq)的值是8,所以这个表达式等价于ppq + 7。按照指针算术的规则,这会偏移 7 × sizeof(int*) = 7×8 = 56 字节。你的起始地址是0x7ff7bfeff150,加56字节就是0x7ff7bfeff150 + 0x38 = 0x7ff7bfeff188——这就是你得到错误结果的原因,你以为是直接加字节数,但实际上指针算术把你的偏移量按指针指向类型的大小放大了。
第一段正确代码为什么能行?
再看这段代码:
char* lastByte = (char*)(ppq) + sizeof(ppq) - 1;
这里的关键操作是把ppq转换成了char*类型:C++里char的大小固定是1字节,所以char*类型的指针做算术运算时,偏移量就是你写的整数本身(按1字节为单位)。sizeof(ppq)是8,所以(char*)(ppq) +7就是在起始地址基础上加7字节,正好指向ppq这个指针变量占用的最后一个字节的地址(因为ppq占8字节,地址范围是0x7ff7bfeff150到0x7ff7bfeff157),这和你输出的结果完全匹配。
另外补充个小细节:第一段代码里用(void*)lastByte来输出地址,是因为如果直接输出char*,会被当成字符串来解析,可能打印出乱码或者空内容,转成void*才能正确打印出内存地址值。
总结一下
要获取任意变量(包括指针变量)的最后一个字节地址,核心是要按字节来计算偏移,所以必须把变量的地址转换成char*(或者unsigned char*)类型——只有这样,指针算术才会以1字节为单位进行偏移,而不是按照原指针指向的类型大小来放大偏移量。
备注:内容来源于stack exchange,提问作者andreimoroz

