免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4255 | 回复: 16
打印 上一主题 下一主题

[C] 关于C语言 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-11-04 01:25 |只看该作者 |倒序浏览
请各位看下面的两个程序

main()

{

int i=5,a;

a=(++i)*(++i)*(++i);

printf("%d",a);

}
它的输出结果是什么呢?答案是  512

请看下面的一个程序


main()

{
int i=5;

printf("%d",(++i)*(++i)*(++i));

}

它的输出结果是什么呢,答案是 336
它的结果与上面的那个为什么不同呢?
高手指点一下吧。

论坛徽章:
0
2 [报告]
发表于 2006-11-04 02:55 |只看该作者
注意赋值的那句

论坛徽章:
0
3 [报告]
发表于 2006-11-04 09:27 |只看该作者
原帖由 sea313081574 于 2006-11-4 01:25 发表
请各位看下面的两个程序

main()

{

int i=5,a;

a=(++i)*(++i)*(++i);

printf("%d",a);

}
它的输出结果是什么呢?答案是  512

请看下面的一个程序


main()

{
int i=5;

...


在同一个编译器中结果应该一样才对,这与具体编译器有关,不同编译器可能有不同结果,最好就别这样写

BTW,你用的啥编译器?

论坛徽章:
0
4 [报告]
发表于 2006-11-04 10:38 |只看该作者
[root@localhost think]# cat a.c
main()

{

int i=5,a;

a=(++i)*(++i)*(++i);

printf("%d\n",a);

}
[root@localhost think]# ./a
392
[root@localhost think]#
#####################################
[root@localhost think]# cat b.c
main()

{
int i=5;

printf("%d\n",(++i)*(++i)*(++i));

}
[root@localhost think]# ./b
392
[root@localhost think]#
上面的是linux,gcc 64位机器上的结果~~
结果是3个8相乘,可不可以给分析一下~~

[ 本帖最后由 小瓶盖儿 于 2006-11-4 10:40 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2006-11-04 12:28 |只看该作者
64*8 = 2^6*2^3 = 2^(6+3) = 2^9 = 2^(10-1) = 1024/2 = 512

结果证明,你得到的不是 3 个 8 相乘

  1. #include <stdio.h>

  2. void
  3. r1()
  4. {
  5.         int i = 5, a;
  6.         a = (++i) * (++i) * (++i);
  7.         printf("%d", a);
  8. }


  9. void
  10. r2()
  11. {
  12.         int i = 5;
  13.         printf("%d", (++i) * (++i) * (++i));
  14. }

  15. int
  16. main(int argc, char **argv)
  17. {
  18.         r1();
  19.         printf("\n");
  20.         r2();
  21.         printf("\n");
  22.         return 0;
  23. }
复制代码

# ./cafds
392
392
#


汇编的结果:
_r1:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        movl $5,-4(%ebp)
        incl -4(%ebp)
        incl -4(%ebp)
        movl -4(%ebp),%eax
        imull -4(%ebp),%eax
        incl -4(%ebp)
        movl %eax,%edx
        imull -4(%ebp),%edx
        movl %edx,-8(%ebp)
        movl -8(%ebp),%eax
        pushl %eax
        pushl $LC0
        call _printf
        addl $8,%esp
L5:
        leave
        ret

_r2:
        pushl %ebp
        movl %esp,%ebp
        subl $4,%esp
        movl $5,-4(%ebp)
        incl -4(%ebp)
        incl -4(%ebp)
        movl -4(%ebp),%eax
        imull -4(%ebp),%eax
        incl -4(%ebp)
        imull -4(%ebp),%eax
        pushl %eax
        pushl $LC0
        call _printf
        addl $8,%esp
L6:
        leave
        ret


以上结果未经过优化。而经过编译器优化后,直接把 392 作为 printf() 的参数了:

_r1:
        pushl %ebp
        movl %esp,%ebp
        pushl $392
        pushl $LC0
        call _printf
        leave
        ret
_r2:
        pushl %ebp
        movl %esp,%ebp
        pushl $392
        pushl $LC0
        call _printf
        leave
        ret


这说明,要么书上有误,要么 gcc 的编译器有毛病。

[ 本帖最后由 langue 于 2006-11-4 12:40 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2006-11-04 14:30 |只看该作者
。。。 。。。

研究这样的问题似乎意义不大,因为具体跟编译器的实现有关,所以,研究这样的结果只是在研究某个编译器的

对这个问题的处理方法而已。

论坛徽章:
0
7 [报告]
发表于 2006-11-04 17:16 |只看该作者
TC2.0编译后和楼主是一样的。

论坛徽章:
0
8 [报告]
发表于 2006-11-04 17:27 |只看该作者
(++i)*(++i)*(++i) 表达式中变量 i 被改变三次,多于一次,因此这是一个无定义的表达式,其结果是不确定的。

>> 在同一个编译器中结果应该一样才对

这个结论是得不到保证的。优化选项的不同、执行程序是调试版还是发行版等因素也可能会对结果造成影响。记住:对于未定义行为最好不要对其结果作出任何假设。

>> 这说明,要么书上有误,要么 gcc 的编译器有毛病。

由于程序中的表达式是无定义的,所以是否能够得到一个结果、如果得到结果的话其值是多少等等都是实现相关的。编译器对此进行的任何实现都是被标准所允许的,即编译器无论如何实现都是没有“毛病”的。有毛病的只能是人——写程序的人应该保证自己的程序中不会出现任何未定义的行为。

>> 研究这样的问题似乎意义不大

经常看到持这种观点的人。正确的说法是:研究类似(无定义行为)问题的结果是没有意义的,然而能够区分什么是无定义行为是有实际意义的。对初学者而言可能这个问题显得有些深奥,可暂时不作更高的要求;但是对于一个程序员来说,如果他不清楚“无定义”(undefined)的概念,那就不可能阻止在他的程序中出现无定义的表达式(比如写出(++i)*(++i)*(++i) 这样无定义的表达式),从而可能造成很难查找的程序错误和隐患。

论坛徽章:
0
9 [报告]
发表于 2006-11-04 17:39 |只看该作者
原帖由 whyglinux 于 2006-11-4 17:27 发表
(++i)*(++i)*(++i) 表达式中变量 i 被改变三次,多于一次,因此这是一个无定义的表达式,其结果是不确定的。

>> 在同一个编译器中结果应该一样才对

这个结论是得不到保证的。优化选项的不同、执行程序 ...


:wink: 你的“无定义”一词出自哪? c 标准? 还是 c++ 标准? 还是你的定义? 或者是你的经验之谈?

论坛徽章:
0
10 [报告]
发表于 2006-11-04 18:29 |只看该作者
>> 你的“无定义”一词出自哪? c 标准? 还是 c++ 标准? 还是你的定义? 或者是你的经验之谈?

“无定义”或“未定义”(undefined)是 C/C++ 标准中广泛使用的一个术语,用于指代语法错误之外的一种错误现象。

对于无定义的程序代码,其执行的结果产生的是“无定义行为”(undefined behaviour),即标准对于执行结果不作任何要求(这就是 undefined 的由来—— undefined by the standard),而是放权给编译器任其自由实现。例如,被零除、数组访问越界以及上面提到的表达式等都是未定义的。

可以找一份 C 或者 C++ 标准、或者在网上找一些相关资料来了解这个概念。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP