免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: zx_wing
打印 上一主题 下一主题

大家来看看这个程序,解释出原因了就明白指针和数组的区别了(程序很短) [复制链接]

论坛徽章:
7
荣誉版主
日期:2011-11-23 16:44:17子鼠
日期:2014-07-24 15:38:07狮子座
日期:2014-07-24 11:00:54巨蟹座
日期:2014-07-21 19:03:10双子座
日期:2014-05-22 12:00:09卯兔
日期:2014-05-08 19:43:17卯兔
日期:2014-08-22 13:39:09
21 [报告]
发表于 2006-12-18 09:55 |只看该作者
这里的a++其实就没有任何动作
  1. int a = 1;
  2.   sizeof(a++);
复制代码

BTW:主要想说sizeof是编译时的事,不要被它迷惑了。

论坛徽章:
0
22 [报告]
发表于 2006-12-18 11:32 |只看该作者
大家看看这个帖子,好像没那么复杂。

http://blogger.org.cn/blog/more.asp?name=newqiang&id=11178

论坛徽章:
0
23 [报告]
发表于 2006-12-18 12:58 |只看该作者
原帖由 whyglinux 于 2006-12-18 09:41 发表
>> int a = 1; a++;
>> 我可以肯定的说上述代码不需要访存,因为我没有给出上下文环境以及平台,所以总能找出一种不需要访存的情况。

何出此言?为了进行 a++ 的计算,总是首先要从内存中取得 a  ...


首先我希望明确一个容易误解的概念:通常认为局部变量是放在栈上的,但实际不是这样。当局部变量的个数少于程序寄存器的个数时,变量会放在寄存器堆上,而不是栈上。所以,我如果把上面的代码这样写:

  1. void test()
  2. {
  3.      int a = 1;
  4.      a++;
  5. }
复制代码

有兴趣的朋友可以自己看看反汇编,会发现没有访存操作,a是放在一个寄存器里的(在x86平台上,我推测是eax)。

是我说的第一点,我没给出上下文。

其次,即使我程序这样写:

  1. void test()
  2. {
  3.       int a1 = 1;
  4.       int a2 = 2;
  5.       int a3 = 3;
  6.       int a4 = 4;
  7.       int a5 = 5;
  8.       int a6 = 6;
  9.       int a7 = 7;
  10.       int a8 = 8;
  11. }
复制代码

上面的变量是放在栈上吗?熟悉x86的朋友肯定会说,有部分放在栈上,因为寄存器溢出了。寄存器溢出是指变量个数超过程序寄存器个数的情况,这个时候部分变量会放到栈上去。像x86架构下,程序寄存器有8个,除去用做框架指针和栈指针的ebp和esp外,有6个可用。上述程序有8个变量,就会有两个放到栈上。但是我还是可以说它们不在栈上,前提条件是例如程序运行在IA64平台上。IA64平台共128个通用寄存器,除去32个系统可能会做特殊用途的外,还有96个可用。所以上面的程序也不会造成寄存器溢出,所有变量在寄存器堆上。这个就是我所说的第二点,我没有指定平台。

有个c中存在但很少被用的关键字:register,就是告诉编译器这个变量经常用到,把它放到寄存器中以提高效率。

所以说,光从语言的角度很多东西是讲不清楚的,例如数组和指针。再经典的教材只要是讲语言的,都不会把本质的东西讲的很清楚,这就造成了很多东西看上去一样,但实际是不一样的。

纠正上面的错误:和编译器行为有关,没有优化的时候可能是会访存的。优化级别高了上述代码会完全被优化掉。这是我例子举的不好,这里主要是想说明局部变量不一定在栈上。为了不造成误导,特指出上面的错误。

[ 本帖最后由 zx_wing 于 2006-12-18 14:02 编辑 ]

论坛徽章:
7
荣誉版主
日期:2011-11-23 16:44:17子鼠
日期:2014-07-24 15:38:07狮子座
日期:2014-07-24 11:00:54巨蟹座
日期:2014-07-21 19:03:10双子座
日期:2014-05-22 12:00:09卯兔
日期:2014-05-08 19:43:17卯兔
日期:2014-08-22 13:39:09
24 [报告]
发表于 2006-12-18 13:14 |只看该作者
下面这个是立即数
  1. (int*)0 + 10
  2. &x + 10  // x 是一个静态对象。
复制代码

如果没有猜错的话,上面的如果作为右值的话,编译器会运算出结果,而目标代码中只有这个结果。

  1.      int a = 1;
  2.      a++;
  3. }
复制代码

这个和立即数不是一个概念。
编译器不会做预先计算,而是生成增一指令或add指令,由处理器在运行时运算。

论坛徽章:
0
25 [报告]
发表于 2006-12-18 13:16 |只看该作者
To zx_wing

>> 有兴趣的朋友可以自己看看反汇编,会发现没有访存操作,a是放在一个寄存器里的(在x86平台上,我推测是eax)。

真的没有访存操作操作吗?那寄存器中的初始值是从哪里来的?

论坛徽章:
0
26 [报告]
发表于 2006-12-18 13:21 |只看该作者
有兴趣的朋友可以自己看看反汇编,会发现没有访存操作,a是放在一个寄存器里的(在x86平台上,我推测是eax)。


zx_wing这位朋友还是推测出来的,即使是放在 eax 也不能说明什么问题,gcc 根据情况而定

想要深入了解清楚,看gcc实现代码

论坛徽章:
0
27 [报告]
发表于 2006-12-18 13:22 |只看该作者
原帖由 r2007 于 2006-12-18 13:14 发表
下面这个是立即数
  1. (int*)0 + 10
  2. &x + 10  // x 是一个静态对象。
复制代码

如果没有猜错的话,上面的如果作为右值的话,编译器会运算出结果,而目标代码中只有这个结果。

[code]     int a = 1;
  ...


是的,上面其实都是常量操作,静态变量x的地址在编译时就确定了,所以是立即数操作。

它们本身就不是一个东西,我只是想说明单纯的讨论是否访存没有意义。所以不要脱离指针和数组的范围来讨论这个问题。

论坛徽章:
0
28 [报告]
发表于 2006-12-18 13:22 |只看该作者
x86上,c语言从来不把寄存器变量放到eax, ebx, ecx, edx
它们只存在于edi,esi,所以编写程序从来不要指望寄存器变量会多于两个,而且,让编译器自动优化比人工控制好得多。

论坛徽章:
0
29 [报告]
发表于 2006-12-18 13:23 |只看该作者
原帖由 whyglinux 于 2006-12-18 13:16 发表
To zx_wing

>> 有兴趣的朋友可以自己看看反汇编,会发现没有访存操作,a是放在一个寄存器里的(在x86平台上,我推测是eax)。

真的没有访存操作操作吗?那寄存器中的初始值是从哪里来的?


编译过后,初始化操作会被转换成一个立即数操作,例如:
mov $1, %eax

[ 本帖最后由 zx_wing 于 2006-12-18 13:58 编辑 ]

论坛徽章:
0
30 [报告]
发表于 2006-12-18 13:25 |只看该作者
原帖由 mik 于 2006-12-18 13:21 发表


zx_wing这位朋友还是推测出来的,即使是放在 eax 也不能说明什么问题,gcc 根据情况而定

想要深入了解清楚,看gcc实现代码


是的,不具备任何意义。
嘿嘿,我之所以这样推测是因为我也是用gcc,很多程序习惯上编译出来后是这样用的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP