C、C++中指针加 1 的问题
2004-11-24 11:25
411 查看
先用贝尔的一道笔试题简要的说明一下吧:
【题】说明以下程序。
#include <stdio.h><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
int main(void)
{
unsigned int a[3] = {0x01020304, 0x05060708, 0x090a0b0c};
unsigned int *p = (unsigned int *)((int)a +1);①
printf("%x/n", *p);
return 0;
}
【题目解析】
这段程序的输出结果应该是 8010203(即0x08010203)。
内存存储结构如(图1)所示(在 big-endian 的系统中)。在①处的语句中,首先把数组 a 的首地址转化为整型,然后再加 1 ,再强制转化为 (unsigned int *) ,这个时候 p 值应该是 0x1235,所以取的是从 0x1235 到 0x1238 四个字节组成的新的整数,所以就是 0x08010203。
给出公式的话就是 (a[0]>>8 | a[1]<<24)。
图 1 内存结构示意图
【补充说明】
看一下这条语句输出是什么呢?
p = a;
printf("%d %08x %d %d %d",
(p+1)-p, *(p+1), &a[1]-&a[0],(int)(p+1)-(int)p, (char *)(p+1)-(char *)p );
结果是: 1 05060708 1 4 4
第一个输出大家可能理解为理所当然了,我们先看后面的结果。
第二个输出值是数组 a 的 a[1] 元素的值,也就是说 (p+1) 指向的地址是 0x1238,而不是0x1235。为什么呢?因为指针加 1 的时候,实际上是加上了他所指向数据类型的宽度,这样指针就可以指向下一个元素而不是一个元素的一半了。汇编代码如下:
0040106A mov ecx,dword ptr [ebp-10h]
0040106D add ecx,4 ;注意这里,实际加的是 4,而不是1
00401070 sub ecx,dword ptr [ebp-10h]
00401073 sar ecx,2
00401076 push ecx
第三个输出按理来说应该是 0x1238-0x1234 = 4,但是为什么是 1 呢?因为返回的是这种元素的个数,而不是真正的地址差值,也就是把差值再除以元素宽度。下面是 VC 的汇编代码,参数 &a[1]-&a[0] 的压栈过程。
00401043 lea ecx,[ebp-8] ; 取 a[1] 的地址值
00401046 lea edx,[ebp-0Ch] ; 取 a[0] 的地址值
00401049 sub ecx,edx ; 计算地址值之差,并放入 ecx 中 (值为4)
0040104B sar ecx,2 ; 将 ecx 中的数值右移两位,也就是除以 4 (值为1)
0040104E push ecx ; 参数压栈,供函数 printf() 使用
第四个输出是 4,因为int类型的相减就是实际数字的相减,不需考虑其它因素,汇编代码如下:
00401063 mov edx,dword ptr [ebp-10h]
00401066 mov eax,dword ptr [edx+4]
00401069 push eax ; 注意!压栈之前没有右移操作
第五个输出,讲到这里 我想大家应该都明白了为什么是4了,我只给出汇编代码:
0040104F mov eax,dword ptr [ebp-10h]
00401052 add eax,4
00401055 sub eax,dword ptr [ebp-10h]
00401058 push eax
现在在回头看一下第一个输出结果的汇编代码。在执行 p+1 的时候实际上是加了 4 (int类型的宽度),只是在减的时候将结果除了个 4,所以结果仍然是 1。
;(p+1)-p
0040106A mov ecx,dword ptr [ebp-10h]
0040106D add ecx,4
00401070 sub ecx,dword ptr [ebp-10h]
00401073 sar ecx,2
00401076 push ecx
【后记】
这些以前都有点印象,但是不是十分确定,昨天就试验了一下,找出了一下规律。其实这些 C99 上应该都有的,我同学正在帮我找,找到了将链接贴到这里。
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. (结果是两个数组元素的下标之差)
【题】说明以下程序。
#include <stdio.h><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
int main(void)
{
unsigned int a[3] = {0x01020304, 0x05060708, 0x090a0b0c};
unsigned int *p = (unsigned int *)((int)a +1);①
printf("%x/n", *p);
return 0;
}
【题目解析】
这段程序的输出结果应该是 8010203(即0x08010203)。
内存存储结构如(图1)所示(在 big-endian 的系统中)。在①处的语句中,首先把数组 a 的首地址转化为整型,然后再加 1 ,再强制转化为 (unsigned int *) ,这个时候 p 值应该是 0x1235,所以取的是从 0x1235 到 0x1238 四个字节组成的新的整数,所以就是 0x08010203。
给出公式的话就是 (a[0]>>8 | a[1]<<24)。
图 1 内存结构示意图
【补充说明】
看一下这条语句输出是什么呢?
p = a;
printf("%d %08x %d %d %d",
(p+1)-p, *(p+1), &a[1]-&a[0],(int)(p+1)-(int)p, (char *)(p+1)-(char *)p );
结果是: 1 05060708 1 4 4
第一个输出大家可能理解为理所当然了,我们先看后面的结果。
第二个输出值是数组 a 的 a[1] 元素的值,也就是说 (p+1) 指向的地址是 0x1238,而不是0x1235。为什么呢?因为指针加 1 的时候,实际上是加上了他所指向数据类型的宽度,这样指针就可以指向下一个元素而不是一个元素的一半了。汇编代码如下:
0040106A mov ecx,dword ptr [ebp-10h]
0040106D add ecx,4 ;注意这里,实际加的是 4,而不是1
00401070 sub ecx,dword ptr [ebp-10h]
00401073 sar ecx,2
00401076 push ecx
第三个输出按理来说应该是 0x1238-0x1234 = 4,但是为什么是 1 呢?因为返回的是这种元素的个数,而不是真正的地址差值,也就是把差值再除以元素宽度。下面是 VC 的汇编代码,参数 &a[1]-&a[0] 的压栈过程。
00401043 lea ecx,[ebp-8] ; 取 a[1] 的地址值
00401046 lea edx,[ebp-0Ch] ; 取 a[0] 的地址值
00401049 sub ecx,edx ; 计算地址值之差,并放入 ecx 中 (值为4)
0040104B sar ecx,2 ; 将 ecx 中的数值右移两位,也就是除以 4 (值为1)
0040104E push ecx ; 参数压栈,供函数 printf() 使用
第四个输出是 4,因为int类型的相减就是实际数字的相减,不需考虑其它因素,汇编代码如下:
00401063 mov edx,dword ptr [ebp-10h]
00401066 mov eax,dword ptr [edx+4]
00401069 push eax ; 注意!压栈之前没有右移操作
第五个输出,讲到这里 我想大家应该都明白了为什么是4了,我只给出汇编代码:
0040104F mov eax,dword ptr [ebp-10h]
00401052 add eax,4
00401055 sub eax,dword ptr [ebp-10h]
00401058 push eax
现在在回头看一下第一个输出结果的汇编代码。在执行 p+1 的时候实际上是加了 4 (int类型的宽度),只是在减的时候将结果除了个 4,所以结果仍然是 1。
;(p+1)-p
0040106A mov ecx,dword ptr [ebp-10h]
0040106D add ecx,4
00401070 sub ecx,dword ptr [ebp-10h]
00401073 sar ecx,2
00401076 push ecx
【后记】
这些以前都有点印象,但是不是十分确定,昨天就试验了一下,找出了一下规律。其实这些 C99 上应该都有的,我同学正在帮我找,找到了将链接贴到这里。
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. (结果是两个数组元素的下标之差)
相关文章推荐
- C++算法系列之日历生成的算法代码
- 千年零一虫
- 主引导扇区释疑
- 一个非常不错的业务规则管理器
- 帮帮我好不好!!!!
- 关于数据库备份的问题!
- 在做控件的存取控制时碰到的问题,请教各位!
- 输入输出流为什么要用缓冲区?
- 引用一个人的说法看中国软件需求基础
- 力争最简单把*、&说清楚
- set()的用法小介
- 非对称加密算法中求解大正整数模大正整数的余数的快速计算法
- 看到一篇好文章与大家分享!!!!!
- 一种基于R-Tree的改进多维索引[待正稿]
- 纯编码实现数据库的建立或压缩
- Decal SDL-Delphi的范型类库-通用数据结构与算法类库(一)
- thinking in c++ 卷2
- thinking in c++卷2
- thinkng in c++卷2