拈花小仙 发表于 2014-3-28 18:49:11

C语言的一个小问题

本帖最后由 拈花小仙 于 2014-7-6 00:37 编辑

#include <stdio.h>
int main()
{
int a={1,2,3,4};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}

输出结果
4,2000000

为什么是这样的结果,请详细说明下,谢谢!
C++编程小组

CS007 发表于 2014-3-28 18:49:12

在x86系统下,输出的值为多少?
#include<stdio.h>
int main()
{
int a={1,2,3,4,5,6,7,8,9};
int*ptr1=(int*)(&a+1);
int*ptr2=(int*)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
可以告诉大家的是答案是:
9,2000000
问题来,为什么是9和2000000 。这个答案估计是没有人能够料想得到的吧!如果你以前从来没有看过这个问题,现在一眼就看出这个问题的答案的话,那么你就是传说中顶尖高手中的高手,C语言已经达到如火纯青的地步。难得的人才啊!其实这里有很多的问题需要解决,这不是一道普通的C语言的题目,而是一题高级的C语言题目,它涉及的知识面都让我震惊。这个输出的结果会让很多写过C语言的同学感到困惑不已!
      为了解决这个问题,你至少需要懂得如何去断点调试和看懂反汇编代码。为了更好地理解这段代码,我们需要将VC6.0对这段的C语言代码的反汇编代码拿出来研究一番。
4:      int a={1,2,3,4,5,6,7,8,9};
00401028   mov         dword ptr ,1
0040102F   mov         dword ptr ,2
00401036   mov         dword ptr ,3
0040103D   mov         dword ptr ,4
00401044   mov         dword ptr ,5
0040104B   mov         dword ptr ,6
00401052   mov         dword ptr ,7
00401059   mov         dword ptr ,8
00401060   mov         dword ptr ,9
5:
6:      int*ptr1=(int*)(&a+1);
00401067   lea         eax,
0040106A   mov         dword ptr ,eax
7:
8:      int*ptr2=(int*)((int)a+1);
0040106D   lea         ecx,
00401070   mov         dword ptr ,ecx
9:
10:       printf("%x,%x",ptr1[-1],*ptr2);
00401073   mov         edx,dword ptr
00401076   mov         eax,dword ptr
00401078   push      eax
00401079   mov         ecx,dword ptr
0040107C   mov         edx,dword ptr
0040107F   push      edx
00401080   push      offset string "%x,%x" (0042201c)
00401085   call      printf (004010b0)
0040108A   add         esp,0Ch
通过这段汇编代码,请注意了:&a+1所对应的地址是ebp-28h同时这个要注意判断是大端还是小端的问题。这个时候(int*)(&a+1)就等同于&a+9*sizeof(int) 也就是说下一个内容块了,这就是为什么反编译后有ptr ,eax原因
5:
6:      int*ptr1=(int*)(&a+1);
00401067   lea         eax,1
0040106A   mov         dword ptr ,eax
还有这一段,
7:
8:      int*ptr2=(int*)((int)a+1);
0040106D   lea         ecx,
00401070   mov         dword ptr ,ecx
而ptr1[-1]= *(ptr1 - 1) 由于ptr1是指针,指向数组a后面的下一个元素,而ptr1-1就是ptr1这个指针往前移动一个单位,移动之后这个指针指向了数组a的最后一个元素。所以就有*(ptr1-1)=9。 对于ptr2而言,a是数组首元素的首地址,(int)a即把这个地址强制转换为int型数据,然后(int)a+1很简单,就是int型数据的相加。(int*)((int)a+1)就是再把这个int型的数据再强制型转换为int类型的指针,最后再把这个指针赋给int型的ptr2指针,并且将其打印成十六进制的形式。 这个时候,
数组a的内存布局(16进制):01000000 02000000 03000000 04000000 05000000 06000000
070000000800000009000000
而 (int)a+1是向后移动了一个字节,即000000 02 由于是小端的方式,且以16进制的形式显示,所以就有了2000000的值出来。
9:
10:       printf("%x,%x",ptr1[-1],*ptr2);
00401073   mov         edx,dword ptr
00401076   mov         eax,dword ptr
引用来自chenjieb520--两片森林的技术博客

牡丹花下死做鬼 发表于 2014-3-28 19:57:07

小仙 我记得有人出过这个题目的 诶 后悔当时没收藏了

拈花小仙 发表于 2014-3-28 19:58:21

牡丹花下死做鬼 发表于 2014-3-28 19:57 static/image/common/back.gif
小仙 我记得有人出过这个题目的 诶 后悔当时没收藏了

哦,这是我最近看的一本书的问题 买了本C语言深度解剖,觉得不错,比电子书好,电子书全错字

拈花小仙 发表于 2014-3-28 19:59:17

牡丹花下死做鬼 发表于 2014-3-28 19:57 static/image/common/back.gif
小仙 我记得有人出过这个题目的 诶 后悔当时没收藏了

对了,汇编除了王爽的还有什么好书,关于32位汇编和64位汇编的

牡丹花下死做鬼 发表于 2014-3-28 20:03:23

拈花小仙 发表于 2014-3-28 19:59 static/image/common/back.gif
对了,汇编除了王爽的还有什么好书,关于32位汇编和64位汇编的

介个 我还真的不清楚撒~~ 汇编你也知道的放弃了N次了 应为 学了半天连一个小东西都写不出来 你懂得所以......

swsm 发表于 2014-3-28 20:06:07


#include <stdio.h>
int main()
{
    int a={1,2,3,4};             //定义一个整型数组
   
    printf("a数组的首地址为:%d\n", &a );             //将a数组的地址打印出来
    printf("a数组的首地址加上sizeof(a)的值后的地址为: %d\n", &a + 1);          //将a数组的地址加1后打印出来然后发先地址加了16,经过查资料了解到加的是sizeof(a)的值也就是16
    printf("sizeof(a)的值为: %d \n", sizeof(a));
    int *ptr1=(int *)(&a + 1);      //用ptr1整型指针指向数组a的首地址加1后的位置但不是a的地址是上面所讲的,呵呵
   
    printf("ptr1指针指向的位置的值为: %d\n", *ptr1);
   
    int *ptr3=(int *)((int)a + 1 );   //这里的指针ptr3是指向将a数字的首地址变成int型后再加1后的地址的位置()
    printf("ptr3指针指向的位置的值为: %d\n", ptr3);//将上面的地址打印出来发现地址只是但纯的加1
    int *ptr4=(int *)((int)a + 2 );   //同ptr3再次验证
    printf("ptr4指针指向的位置的值为: %d\n", ptr4);//将上面的地址打印出来发现地址只是但纯的加2


    int *ptr2=(int *)((int)a+1);    //用ptr2整型指针指向将a数字的首地址变成int型后再加1后的地址的位置(注意这里的地址只是加1,上面有验证)
    printf("ptr2指针指向的位置的值为: %d\n", *ptr2);

    printf("ptr1[-2] = %x   , *ptr2 = %x",ptr1[-1],*ptr2);   //而这里的ptr1[-1]等于4 是因为地址减去了4然后到了a = 4的位置
    printf("\n");
   
    printf("验证ptr1[-1] = a,现在打印ptr1[-2]的值:%d\n",ptr1[-2]);


    printf("\n");
   
    return 0;
}
//哎呀,忙了半天,代码详细的验证和写注释了,可是哎!!问题都结束了,不过还是学到了知识,
//呵呵呵

拈花小仙 发表于 2014-3-28 20:08:52

swsm 发表于 2014-3-28 20:06 static/image/common/back.gif
//哎呀,忙了半天,代码详细的验证和写注释了,可是哎!!问题都结束了,不过还是学到了知识,
//呵呵呵

学到知识才是最重要的,我还有个问题呢http://bbs.fishc.com/thread-45311-1-1.html

拈花小仙 发表于 2014-3-28 20:16:43

swsm 发表于 2014-3-28 20:06 static/image/common/back.gif
//哎呀,忙了半天,代码详细的验证和写注释了,可是哎!!问题都结束了,不过还是学到了知识,
//呵呵呵

我的问题比较多,希望以后您能多多帮助{:7_181:}

swsm 发表于 2014-3-28 20:37:51

拈花小仙 发表于 2014-3-28 20:16 static/image/common/back.gif
我的问题比较多,希望以后您能多多帮助

太客气了,我是个菜鸟,我也是在学习的,一起学习吧,我也看了你那个c高深什么,我要仔细的研究一下,呵呵,继续学习吧,有问题我们互相交流,呵呵呵!!!

拈花小仙 发表于 2014-3-28 20:41:34

swsm 发表于 2014-3-28 20:37 static/image/common/back.gif
太客气了,我是个菜鸟,我也是在学习的,一起学习吧,我也看了你那个c高深什么,我要仔细的研究一下,呵呵 ...

{:7_174:}这些题就是那书上的,这书我只能看懂一半多点,还都是些常识性的,还好多困难的地方

oggplay 发表于 2014-3-28 20:59:02

恩,这到题。。。。。我的编译器允许了,但是操作系统把我踢出来了!

拈花小仙 发表于 2014-3-28 21:03:42

oggplay 发表于 2014-3-28 20:59 static/image/common/back.gif
恩,这到题。。。。。我的编译器允许了,但是操作系统把我踢出来了!

您电脑不会只装linux吧

oggplay 发表于 2014-3-28 21:09:12

拈花小仙 发表于 2014-3-28 21:03 static/image/common/back.gif
您电脑不会只装linux吧

windows下不熟悉,还不如这个系统思路清楚

拈花小仙 发表于 2014-3-28 21:11:46

oggplay 发表于 2014-3-28 21:09 static/image/common/back.gif
windows下不熟悉,还不如这个系统思路清楚

哦,我发现我好友里高手真多,嘻
页: [1]
查看完整版本: C语言的一个小问题