搜索
查看: 1725|回复: 19
打印 上一主题 下一主题

大神们来解释下这个奇葩的语句。

[复制链接]
跳转到指定楼层
楼主
发表于 2013-12-31 12:08:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
30啊哈币
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. int main()
  4. {
  5.     int i=8;
  6.     printf("%d\n%d\n%d\n%d\n%d\n%d\n%d\n",i,++i,--i,i++,i--,-i++,-i--);
  7.     return 0;
  8. }
复制代码


最佳答案

查看完整内容

首先要明白,并非所有能通过编译的代码都是正确的代码 这种时点有问题的代码,gcc会给警告的 我强烈推荐新人用-Wall -ansi -pedantic参数编译自己的代码,学习一两星期后可以考虑用-Werror -ansi -pedantic参数 然后要明白,像++i,i--这种代码,并没有想象中的那么简单 i--确实是先取i的值,然后把i的值减少1。但是减少这一步,在什么时候去做呢? ISO C仅仅规定,必须在下一个时序点(sequence point)前完成这步操作 例 ...
沙发
发表于 2013-12-31 12:08:24 | 只看该作者
首先要明白,并非所有能通过编译的代码都是正确的代码
这种时点有问题的代码,gcc会给警告的
我强烈推荐新人用-Wall -ansi -pedantic参数编译自己的代码,学习一两星期后可以考虑用-Werror -ansi -pedantic参数

然后要明白,像++i,i--这种代码,并没有想象中的那么简单
i--确实是先取i的值,然后把i的值减少1。但是减少这一步,在什么时候去做呢?
ISO C仅仅规定,必须在下一个时序点(sequence point)前完成这步操作

例如 i++; 分号有一个时序点,所以可以确认,在分号后面,i的值已经改变了
再比如 i=1; i=++i, i--; 逗号有一个时序点,所以可以确定,在i--的时候,i的值已经是2了
但是例如i=1; i=i++; 只有分号的一个时序点,++带来的自增在什么时候处理?是=处理之前还是之后?不知道,标准没有规定这时候该怎么办,只是说这是未定义行为(undefined behavior)

什么是未定义行为?如果在看这个帖子的你不是小学生,学过初中教的函数,请回答这个问题:
y = x (x > 0) 在x = -2 时的函数值是多少?
出了定义域?这个问题本身是错的?是的,
printf("%d\n%d\n%d\n%d\n%d\n%d\n%d\n",i,++i,--i,i++,i--,-i++,-i--);
的输出结果是性质类似的问题

如果不理解函数定义域的概念,小学数学里也有类似概念
5 / 0 = ? 如果你觉得是题目印错了,那么到这里就可以了
如果你觉得是无穷大,那么只能告诉你,除以0得无穷大是高等数学没学懂的人以讹传讹搞出来的说法

未定义行为隐含的语义是,一个合格的程序员不应该写出这种不合理的代码,编译器这时候没义务给你产生正确的汇编/机器码,也没义务告诉你这代码是有问题的

点评

mark  发表于 2014-7-22 12:49
高!  发表于 2014-1-2 08:36
板凳
发表于 2013-12-31 12:40:26 | 只看该作者
未定义
编译器有权自行处理
地板
发表于 2013-12-31 15:27:54 | 只看该作者
i++的意思是,先执行赋值语句,i再自加
++i的意思是,i先自加,再执行赋值语句
所以最后的输出就是:
  1. 8 8 8 7 8 -7 -8
复制代码

点评

...我其实想说第2句点评没想到两个一起出来了...=_=  发表于 2014-1-1 08:47
你可能很疑惑对吧!看C的话看不懂的话。反汇编看下这段代码....。  发表于 2014-1-1 08:44
反汇编这段代码你会有撞墙的冲动....先不要反驳rosynirvana大神!  发表于 2014-1-1 08:43
5#
发表于 2013-12-31 17:29:23 | 只看该作者
4399APPLE 发表于 2013-12-31 15:27
i++的意思是,先执行赋值语句,i再自加
++i的意思是,i先自加,再执行赋值语句
所以最后的输出就是:

别扯了,函数传参的时候逗号没时点,两个紧邻时点间一个变量的值被改变6次,这是典型的未定义行为
6#
发表于 2014-1-9 09:34:35 | 只看该作者
rosynirvana 发表于 2013-12-31 12:08
首先要明白,并非所有能通过编译的代码都是正确的代码
这种时点有问题的代码,gcc会给警告的
我强烈推荐 ...

懂了,3Q
我还是小学生
7#
发表于 2014-7-22 08:38:09 | 只看该作者
rosynirvana 发表于 2013-12-31 12:08
首先要明白,并非所有能通过编译的代码都是正确的代码
这种时点有问题的代码,gcc会给警告的
我强烈推荐 ...

我个人理解:

像自增自减这类的表达式,他原先的设计思想是简化程序,而不是像楼主举例的把程序复杂化。

i++,一个表达式隐含了两种含义,也即两个计算动作,两个计算动作必定有先后顺序,所以单独为简化程序而诞生,所以应用时要注意。写程序应当以别人和自己易懂的方式准确、清晰的表达。
8#
发表于 2014-7-22 09:34:37 | 只看该作者
嗨,强哥! 发表于 2014-7-22 08:38
我个人理解:

像自增自减这类的表达式,他原先的设计思想是简化程序,而不是像楼主举例的把程序复杂化 ...

可惜国内考试喜欢考这种东西
而且出题人自己也不知道是标准中怎么规定的
9#
发表于 2014-7-22 10:06:26 | 只看该作者
rosynirvana 发表于 2014-7-22 09:34
可惜国内考试喜欢考这种东西
而且出题人自己也不知道是标准中怎么规定的

看了你关于自增的解释,第一次知道了程序执行的时序问题,以及语句执行的时序。

i++; ++i 在后面没有 ';' 符号的时候可能会产生不了动作。
10#
发表于 2014-7-22 10:13:03 | 只看该作者
嗨,强哥! 发表于 2014-7-22 10:06
看了你关于自增的解释,第一次知道了程序执行的时序问题,以及语句执行的时序。

i++; ++i 在后面没有  ...

时序点不只有分号有
例如&&也有
j = i ++ && -- i;

逗号表达式的逗号也有
j = i++, --i, ++i, i--;

上面两句都没问题

但是作为参数分割的冒号就没有,例如主楼
例如printf("%d %d", i++, --i);

我背不下来所有有时序点的情况
实际写程序的时候也没人这么写,如果代码要给别人看,那就一定要写得能让人一眼看懂

如果不是国内考试喜欢这些东西,这种话题就只有研究编译器的人才会讨论了
11#
发表于 2014-7-22 11:10:36 | 只看该作者
rosynirvana 发表于 2014-7-22 10:13
时序点不只有分号有
例如&&也有
j = i ++ && -- i;

时序点不只有分号有
例如&&也有
j = i ++ && -- i;  

逗号表达式的逗号也有
j = i++, --i, ++i, i--;

------->这两例题算是运算符的优先级别问题;还是计算动作的时序问题?


但是作为参数分割的冒号就没有,例如主楼-------->应该说逗号吧?
例如printf("%d %d", i++, --i);
12#
发表于 2014-7-22 11:17:28 | 只看该作者
本帖最后由 rosynirvana 于 2014-7-22 12:56 编辑
嗨,强哥! 发表于 2014-7-22 11:10
时序点不只有分号有
例如&&也有
j = i ++ && -- i;  

时序问题,对比一下就知道了

j = i++ && --i;不会有问题
j = (i++) + (--i); 就是未定义了

下面一个是逗号,我满脑子都是comma……
13#
发表于 2014-7-22 14:04:40 | 只看该作者
本帖最后由 嗨,强哥! 于 2014-7-22 14:06 编辑
rosynirvana 发表于 2014-7-22 11:17
时序问题,对比一下就知道了

j = i++ && --i;不会有问题

[mw_shl_code=c,true]#include <stdio.h>
#include <stdlib.h>
int main()
{
    int j, k, i= 1;
    j = --i && i++;
    k = (i++) + (--i);
    printf ("%d  %d  ", j, k);      //运算结果:0 -2
    system("pause");
    return 0;
}
[/mw_shl_code]
14#
发表于 2014-7-22 16:01:08 | 只看该作者
嗨,强哥! 发表于 2014-7-22 14:04
[mw_shl_code=c,true]#include
#include
int main()

j是0没问题
k那句是未定义的
15#
发表于 2014-7-22 16:18:01 | 只看该作者
rosynirvana 发表于 2014-7-22 16:01
j是0没问题
k那句是未定义的

嗯,程序验证你说的是正确的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表