Chinaunix

标题: 为什么把+++拆成++,+而不是+,++ [打印本页]

作者: asker160    时间: 2010-09-27 10:30
标题: 为什么把+++拆成++,+而不是+,++
例如
k=i+++j;
结果是i++,然后+j,赋值给k

gcc和sun编译器测试的结果,都是++给了i而不是j

为什么不是++j,然后+i呢? C/C++标准规定了这个么?
为什么把+++拆成++,+而不是+,++
--------------------------------------------------------
#include<stdio.h>
int main(void){
  int i=0, j=0;
  int k=i+++j;//i++ and i(old value)+j , k is 0.
  printf("i=%d,j=%d,k=%d\n",i,j,k);
  return 0;
}

> ./a.out
i=1,j=0,k=0
作者: 奶茶dsk    时间: 2010-09-27 10:33
贪心,
作者: hellioncu    时间: 2010-09-27 10:34
最大匹配
作者: noword2k    时间: 2010-09-27 10:37
要用++,就单独一行。
i++;

简单明了,没有任何副作用。

你是在编程,不是在当孔乙己。
作者: houtinghua    时间: 2010-09-27 10:44
贪婪算法吧
作者: davelv    时间: 2010-09-27 11:13
参考《C缺陷和陷阱》1.3节,词法分析中的贪心法
作者: 雨过白鹭洲    时间: 2010-09-27 11:15
那帮大佬们坐在一起闲扯,基本上就是这么定的。。

咱们也只能就这么认了。。
作者: CountOnMyself    时间: 2010-09-27 11:30
回复 1# asker160

又是这种运算符优先级问题,前几天某“砖家”就因为没弄清楚就发贴大放厥词,没想到还真有这么多人不了解C语言的15个运算符优先级的知识。
好吧,算个多事再说一次:
单目运算符的优先级是2;
*,/,%的优先级是3;
+, - 的优先级是4;
这三组运算符的排列是由高到低,所以:
x+++y, 由于++的优先级高于+,必然是解析成(x++)+y,而不可能是x+(++y);
同样地,x*y+z, 也必然是解析成(x*y)+z,而不是x*(y+z)。
原则都是同一个,只要当前运算符的优先级高于或等于下一级,则表达式解析器要先进行归纳,否则要继续右移。
作者: cjaizss    时间: 2010-09-27 11:43
贪婪原则,尽管此语句没有任何歧义,但我建议不要这么写。
作者: fender0107401    时间: 2010-09-27 11:50
我觉得关键在于某些教材上总强调这种无聊的事情,

这么写纯粹是标准的害人害己。
作者: CountOnMyself    时间: 2010-09-27 12:10
我觉得关键在于某些教材上总强调这种无聊的事情,

这么写纯粹是标准的害人害己。
fender0107401 发表于 2010-09-27 11:50



虽然单目运算符比绝大部分运算符的优先级高,但经常使用楼主的这种编程风格的话,有时候再资深的人也会产生误判,所以比较好的风格应该是单目运算符++,--尽量单独一行为好。
作者: davelv    时间: 2010-09-27 12:58
回复  asker160

又是这种运算符优先级问题,前几天某“砖家”就因为没弄清楚就发贴大放厥词,没想到还真 ...
CountOnMyself 发表于 2010-09-27 11:30

关运算符优先级何事,你还真是砖家 --!
作者: 奶茶dsk    时间: 2010-09-27 13:45
本帖最后由 奶茶dsk 于 2010-09-27 13:46 编辑

回复 8# CountOnMyself


    {:3_191:}  按照您的理解是不是说a+++++b就被词法分析成a++ + ++b,,,杯具,,
作者: 奶茶dsk    时间: 2010-09-27 13:46
{:3_198:} 8楼还是多读点书吧,
作者: CountOnMyself    时间: 2010-09-27 19:08
8楼还是多读点书吧,
奶茶dsk 发表于 2010-09-27 13:46



都已经讲了++优先于+了,你居然还可以将a+++++b分析成a++, +, ++b,不得不怀疑你的智商是有问题。
词法分析的结果肯定是a++, ++, +, b, 因为a++不是左值,语法分析时必然在第二个++出现解析错误,   阁下提议别人多读书前先修修自已的脑吧,恐怕是进水了。
作者: fender0107401    时间: 2010-09-27 19:17
最讨厌优先级别问题。
作者: babywolfh    时间: 2010-09-27 19:20
最大贪婪原则
作者: pmerofc    时间: 2010-09-27 20:06
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2010-09-27 20:09
提示: 作者被禁止或删除 内容自动屏蔽
作者: davelv    时间: 2010-09-27 20:18
人家可是知道“C语言的15个运算符优先级”的哦

PS:C语言运算符根本就不是15个优先级
pmerofc 发表于 2010-09-27 20:09


据参考手册上应该是16级
作者: pmerofc    时间: 2010-09-27 20:23
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2010-09-27 20:25
提示: 作者被禁止或删除 内容自动屏蔽
作者: 奶茶dsk    时间: 2010-09-27 20:41
都已经讲了++优先于+了,你居然还可以将a+++++b分析成a++, +, ++b,不得不怀疑你的智商是有问题。
词 ...
CountOnMyself 发表于 2010-09-27 19:08


神奇的解释,,,

最早也得在语义分析阶段才起作用的运算符优先级关系,居然被您老拿来作词法分析了,还和哥谈智商,
您老智商果然奇特,,我呸,,{:3_197:}
作者: zhaohongjian000    时间: 2010-09-27 20:46
8楼真实悲剧,您这手在这地不太管用,要不先学学编译原理?
作者: CountOnMyself    时间: 2010-09-27 22:12
人家可是知道“C语言的15个运算符优先级”的哦

PS:C语言运算符根本就不是15个优先级
pmerofc 发表于 2010-09-27 20:09


随便在googlec搜索一下“C语言运算符优先级”都能找出一大堆链接,跟你这类SB没什么好讨论的,自已一边看去:
http://www.slyar.com/blog/c-operator-priority.html
如果没有运算符的优先级的定义,那么以楼主的问题随便换成另外一个单目运算符的话,比如a+++b换!a+b时,那么你告诉我,该分解成!a, +b,还是a+b再!啊?
这些问题确实是幼儿园级的问题,说人家CSDN是幼儿,阁下就是著名厚脸皮的“IT凤姐”罢了。
作者: pmerofc    时间: 2010-09-27 22:16
提示: 作者被禁止或删除 内容自动屏蔽
作者: CountOnMyself    时间: 2010-09-27 22:55
神奇的解释,,,

最早也得在语义分析阶段才起作用的运算符优先级关系,居然被您老拿来作词法分析了 ...
奶茶dsk 发表于 2010-09-27 20:41


最烦有些人动不动就以专家自居,封杀他人意见。本来对C语言表达式的阅读和理解,在教学目标中根本就不可能要求学员掌握了编译原理才能掌握,只需要扎实掌握入门知识就可以正确理解。
但既然这么多以编译原理专家自居的人跳出来指手划脚且非要将此问题上升到编译原理高度,刚好我也稍懂这方面知识,不妨深入研究一番吧。
楼上说优先级只在语法分析阶段起作用,而在词法分析阶段没作用的“大师”听清楚了。用于词法分析器的优先级,就是“歧义源规则”,一般词法分析器的歧义源规则,按以下次序选择:
   1.  首选最长匹配。
   2. 在匹配相同数目字符的规则中,首选最先给出的规则。
针对楼主所说的++,+,可对照该规则,首先,“++”比“+”长,因此是首选。
其次,按C语言的词法规则的顺序,看看以下片段,也知识"++"在"+"之前
"++"                        { count(); return(INC_OP); }

"--"                        { count(); return(DEC_OP); }

"->"                        { count(); return(PTR_OP); }

"&&"                        { count(); return(AND_OP); }

"||"                        { count(); return(OR_OP); }

"<="                        { count(); return(LE_OP); }

">="                        { count(); return(GE_OP); }

"=="                        { count(); return(EQ_OP); }

"!="                        { count(); return(NE_OP); }

";"                        { count(); return(";"); }

("{"|"<%")                { count(); return("{"); }

("}"|"%>")                { count(); return("}"); }

","                        { count(); return(","); }

":"                        { count(); return(":"); }

"="                        { count(); return("="); }

"("                        { count(); return("("); }

")"                        { count(); return(")"); }

("["|"<:")                { count(); return("["); }

("]"|":>")                { count(); return("]"); }

"."                        { count(); return("."); }

"&"                        { count(); return("&"); }

"!"                        { count(); return("!"); }

"~"                        { count(); return("~"); }

"-"                        { count(); return("-"); }

"+"                        { count(); return("+"); }

"*"                        { count(); return("*"); }

"/"                        { count(); return("/"); }

"%"                        { count(); return("%"); }
因此,无论如何,进行词法分析时,"++"无论是词法分析还是语法分析时,优先级都绝对比"+"高。
各位“编译原理专家”,可看明白了吗?
别动不动就让人学习编译原理什么的,不是所有学习C的人都想做编译器,只是为了应用,以深入浅出的方式让学习者以最简单的方式掌握正确地用法,就是我前面的意图。
优先级+结合性,是最为简单直接的理解C语言表达式的方法,信则用。至于那些“精通”编译原理的专家们,请随便用你们高深的学问去理解好了。
作者: 奶茶dsk    时间: 2010-09-27 23:04
回复 27# CountOnMyself


    早在SF就说了,这个就是词法分析的贪心原则,就您老在扯啥15级的优先级,
真的是没得救了,{:3_197:}
作者: 奶茶dsk    时间: 2010-09-27 23:05
回复 26# pmerofc


    您的长贴获益良多,希望再接再励,继续垒起来,{:3_183:}
作者: CountOnMyself    时间: 2010-09-27 23:12
本帖最后由 CountOnMyself 于 2010-09-27 23:26 编辑
回复  CountOnMyself


    早在SF就说了,这个就是词法分析的贪心原则,就您老在扯啥15级的优先级,
...
奶茶dsk 发表于 2010-09-27 23:04


贪心原则,说白了也是一种优先级选择原则,我从一开始就以大家都能理解的优先级方法来解释,即使是初学者都能明白。正如我前面贴出来的词法规则,其排列顺序其实也就是按照操作符的优先级排序的,这个书本知识并不矛盾,而且好理解。后来某人仁兄将贪心原则这一编译原理的术语直接提出来,我并没有任何反对,是因为这两者并不矛盾,事实即使到了词法和语法层,也无法否定我的说法。
另外,词法分析只解决了如何分解关键字的问题,可没解决操作数和操作符结合顺序的问题,你还是没弄明白优先级的作用,到底是谁没救呢?
由于a++的特殊性不好理解,拿回前面我提到的例子!a+b, 如果没有优先级的话,你能告诉大家,为什么是t=!a, t=t+b, 而不是t=a+b, t=!t;真的与优先级没有一点关系吗?以你对编译原理有所了解,恐怕您心里最明白。
作者: davelv    时间: 2010-09-28 01:13
本帖最后由 davelv 于 2010-09-28 01:16 编辑

看到楼上同学说的这么认真,我觉得也有必要阐述下自己的观点。
运算符优先级是为了处理运算符旁边的表达式的计算顺序而产生的规则,不是为了分割运算符而存在的。是为了语法存在的而不是为了词法存在的。这点前面位也解释了,我不多说。但是楼上同学却把这两个阶段混淆了,虽然上面看起来也算合格,但不正确的解释总是有漏洞。
最能证明这点的应该是C表达式宏观计算上的无序性,这是我自造的术语,可能不好理解,也就是C语言没有规定一个表达式必须从左至右运算,这是明文可考的。
那么你的观点可以解释我从右往左运算的时候a+++b为什么不能被解释成a+ ++b么?
就拿你的例子说事!a + b,这个你把做为矛盾点的运算符分割问题剔除了,本身用运算符和表达式结合的优先级规则就可以解释了。否认你把优先级和分割混为一谈不代表否认运算符优先级。这点可以理解么?

最后,技术问题应该客观对待,参入过多的主观因素对己对人都不好。
作者: zhaohongjian000    时间: 2010-09-28 12:49
为了圆上一句错误的话说这么多,呵呵。
作者: ecjtubaowp    时间: 2010-09-28 14:01
这种写法不知道也罢。
作者: chinesedragon    时间: 2010-09-28 14:04
应该是优先级的问题吧
作者: pmerofc    时间: 2010-09-28 20:29
提示: 作者被禁止或删除 内容自动屏蔽
作者: raiseup.net    时间: 2010-09-29 16:01
回复  asker160

又是这种运算符优先级问题,前几天某“砖家”就因为没弄清楚就发贴大放厥词,没想到还真 ...
CountOnMyself 发表于 2010-09-27 11:30



这个。。。{:3_185:}
不是优先级问题吧
作者: rain_fish    时间: 2010-09-29 20:31
恩,很好的问题。。。。
作者: gtv    时间: 2010-09-29 23:15
回复  asker160

又是这种运算符优先级问题,前几天某“砖家”就因为没弄清楚就发贴大放厥词,没想到还真 ...
CountOnMyself 发表于 2010-09-27 11:30



    学习了
作者: qtdszws    时间: 2010-09-30 10:22
庸人自扰,加括号不就搞定了吗?有意思吗?
作者: VIKING_nb    时间: 2010-09-30 11:08
关优先级屁事!
    劝你还是到CSDN那样的编程幼儿园去忽悠吧
pmerofc 发表于 2010-09-27 20:06



看不过眼,多嘴说一句:CU的某些帖子的提问,同样是幼儿园小班的级别。不要以为CU就很高级很牛X,多尊重一下别人或者别的论坛。
作者: 幻の上帝    时间: 2010-09-30 14:37
有一点可以确定,设计上便于用户理解优先级或者实现上的贪心匹配什么的,都不关语言本身的事。对于语言而言,这就是“规定”,如此而已。
5 [Example: The program fragment x+++++y is parsed as x ++ ++ + y, which, if x and y are of built-in
types, violates a constraint on increment operators, even though the parse x ++ + ++ y might yield a
correct expression. ]
以上是C++03标准2.4一节中的原文。
53) The precedence of operators is not directly specified, but it can be derived from the syntax.
上面这段C++03标准原文是5 Expression的一行注释。
当然,标题里的问题对于人(而不是机器)来说倒仍然是有意义的。不过恐怕也不会因此能找到明确的“正确”答案。非得站在人类的理解或者机器的实现的角度吵着说“错了”的童鞋,都省省吧(根本是鸡同鸭讲嘛)。
按我的理解,根据奥卡姆剃刀原则,这里在语言的框架内讨论+++++是 ++ ++ + 还是 ++ + ++ 这类问题时,根本没必要引入“(运算符)优先级”这一实体概念(也大约因为如此,标准把上面的Example放在根本没有提到“优先级”的2.4而不是5)。这样,即便是要关注人对语言的理解,也没必要考虑“是不是因为优先级的关系”,因为实际上只要按这段注释里面所说的,通过语法约束推导对语义的影响就很容易明确在这里被表达的应该是何种明确的语义了。
要无视标准(这里看起来至少算作是一种建议的理解方法),不愿意这么理解的话也请自便。
(总觉得这倒是比“左值在不需要作为左值就只是右值”“月亮在你不看它时就不存在”之类的要明确多了。)
作者: omycle    时间: 2010-09-30 15:00
回复 8# CountOnMyself


    童鞋,人家都关心背后的故事,你仍然按照小学生的思维啊
作者: KBTiller    时间: 2010-09-30 17:03
楼主问题的本质是确定源代码中究竟有哪些 token
并不是要确定运算符的对象
确实与优先级无关
作者: 幻の上帝    时间: 2010-09-30 18:21
本帖最后由 幻の上帝 于 2010-09-30 18:26 编辑
楼主问题的本质是确定源代码中究竟有哪些 token
并不是要确定运算符的对象
确实与优先级无关
KBTiller 发表于 2010-09-30 17:03


不一定。标题没有限定主语是人还是编译器。
按一般的人类的思维,语法和语义按直觉逻辑的辨识看来是可以多线程乱序执行的(如果知道语法的话)。 于是先看到表达式里面的token还是operator的问题,同各人的“实现”相关。
作者: KBTiller    时间: 2010-09-30 20:53
不一定。标题没有限定主语是人还是编译器。
按一般的人类的思维,语法和语义按直觉逻辑的辨识看来是可 ...
幻の上帝 发表于 2010-09-30 18:21

我觉得程序员恰恰应该摆脱“按一般的人类的思维”
如果是写code,必须事先知道自己要写什么
如果是读code,正确的方式应该是编译器方式。因为程序设计语言不是自然语言,而是一种严格的形式语言

至于您说的多线程,我还没想通您想表达的是什么意思。能否麻烦更具体地说说么
作者: nwl586    时间: 2010-09-30 21:08
后置++比前置++优先级高
比如
int x;
++x++; //应该是编不过的,因为后置++优先级高, 等于下面一个
++(x++);//这个和上面一样,应该编不过,因为x++返回右值,不能自增
(++x)++;//这个可以编过
作者: pmerofc    时间: 2010-10-01 09:58
提示: 作者被禁止或删除 内容自动屏蔽
作者: VIKING_nb    时间: 2010-10-01 12:47
本帖最后由 VIKING_nb 于 2010-10-01 12:53 编辑
逻辑混乱!
    我并没有说CSDN是因为某些幼儿园小班级别的提问而低级,你的所谓“CU的某些帖子 ...
pmerofc 发表于 2010-10-01 09:58


鄙视这个鄙视那个,你岂不是很牛X??????
莫装B,装B遭雷劈。
作者: zhaohongjian000    时间: 2010-10-01 13:12
本帖最后由 zhaohongjian000 于 2010-10-01 17:09 编辑
后置++比前置++优先级高
比如
int x;
++x++; //应该是编不过的,因为后置++优先级高, 等于下面一个
++( ...
nwl586 发表于 2010-09-30 21:08



    麻烦您发贴前试试?而且前后++优先级相同,不同的是左右结合性。
------------------------------------------------------------------
这个地方说错了,前后++的结合性也是相同的,见53楼
作者: nwl586    时间: 2010-10-01 14:50
本帖最后由 nwl586 于 2010-10-01 15:11 编辑
麻烦您发贴前试试?而且前后++优先级相同,不同的是左右结合性。
zhaohongjian000 发表于 2010-10-01 13:12



    谢谢您的提醒,可能是我没说清楚
我的理解是这样的:
优先级是 后置++ > 前置++ > +
所以 x+++y 等于 (x++) + y 而不是 x + (++y)
如果按您所说前后++优先级相同, 它们左右结合性不同,又是怎么不同的呢, 可否写出来证明一下.
据我所知前后++都是右结合性.
再看下面这个例子:
x+++++y;
请问用左右结合性怎么解释它为什么编不过
作者: pmerofc    时间: 2010-10-01 15:24
提示: 作者被禁止或删除 内容自动屏蔽
作者: delimy    时间: 2010-10-01 17:04
j+++i这个表达式的,根据C标准 "the behavior is undefined"
也就是说这是个错误的程序,编译器给出任何结果都可以。

原因是:一个对象在两个顺序点(sequence point)之间只能读写一次。
j++产生一次写j,同时j+++i又有一次读j(并且读出的数据并不是用来改变j的值)这违反了C表达式的限制。


所以根据C标准,j+++i的结果根本不能用来说明任何事情。

如果你们非要具体到编译器的话,就请不要引入C标准说事。
作者: zhaohongjian000    时间: 2010-10-01 17:05
谢谢您的提醒,可能是我没说清楚
我的理解是这样的:
优先级是 后置++ > 前置++ > +
所以 x+++y ...
nwl586 发表于 2010-10-01 14:50



    这个地方我记错了,前后++的结合性相同,正是因为结合性相同,才可以用来消除歧义。
即:相同优先级的操作符拥有相同的结合性,这个时候根据结合性来消歧义

比如
  1. char *p;
  2. *p++;
复制代码
根据结合性,*p++解释为*(p++)

而x+++++x,这个就跟本帖有关了,词法分析的时候因为贪心策略的原因,会被分析成x ++  ++ + x,由于x ++不是一个左值,故而无法通过编译。
作者: delimy    时间: 2010-10-01 17:13
再次重申,像i+++j i++++ 这种表达式 不是习惯好不好的问题 而是根据C标准 这属于未定义的行为 也就是说这根本就是错误的代码。
作者: pmerofc    时间: 2010-10-01 18:18
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2010-10-01 18:28
提示: 作者被禁止或删除 内容自动屏蔽
作者: nwl586    时间: 2010-10-01 19:02
后置++比前置++优先级高  (这个赞成)
    ++x++; //应该是编不过的,因为后置++优先级高, 等于 ...
pmerofc 发表于 2010-10-01 18:28



哥哥啊,谢谢你还赞成我一句
我写了三个
++x++;           //这个我说和下面一句一样,根本原因你看下面一句可好,看来我表达能力有问题啊
++(x++);        //原因写这了,我不该省那句话,应该把原因写两遍,我错了
(++x)++;        //至于这句,是可以编过的,我在VS2008上试过
象我们自己时,都是把前置++返回引用,后置++ 一般用一个临时对象拷贝当前对象,然后调用前置++自增,并返回临时对象
C++内置类型前置++也是返回引用
你可以试试   ++x = 10;
如果GCC编不过的,请指正.谢谢!
作者: delimy    时间: 2010-10-01 19:44
本帖最后由 delimy 于 2010-10-01 20:05 编辑
这个不能苟同
    “一个对象在两个顺序点(sequence point)之间只能读写一次。”与标准说的不一 ...
pmerofc 发表于 2010-10-01 18:18



    ISO 9899 6.5#2:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.


我说的和标准哪里不一致了?

update:
呃,好吧。。。为毛我以为我写的是j+++j...

不淡定的再次飘过。。。
作者: delimy    时间: 2010-10-01 19:47
本帖最后由 delimy 于 2010-10-01 19:50 编辑
哥哥啊,谢谢你还赞成我一句
我写了三个
++x++;           //这个我说和下面一句一样,根本原因你看 ...
nwl586 发表于 2010-10-01 19:02



    你这三个没有一个是语义正确的。
能编译过又怎样?

int *p;
*p = 3;

也能编译过。


不是能C编译器能编译过的就叫C。拜托你们好好读读C标准罢。
作者: pmerofc    时间: 2010-10-01 21:00
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2010-10-01 23:25
提示: 作者被禁止或删除 内容自动屏蔽
作者: bruclan    时间: 2010-10-02 00:33
绝对害人的语句,就不能用个括号吗?这样对大家都好。
作者: tempname2    时间: 2010-10-02 01:22
j+++i这个表达式的,根据C标准 "the behavior is undefined"
也就是说这是个错误的程序,编译器给出任何结果都可以。

原因是:一个对象在两个顺序点(sequence point)之间只能读写一次。
j++产生一次写j,同时j+++i又有一次读j(并且读出的数据并不是用来改变j的值)这违反了C表达式的限制。

delimy 发表于 2010-10-01 17:04


确实跟标准说的不一致呀。

标准里的第一句话说,sequence point之间对象的值只能改变一次;第二句话说,对象被改变之前的值只能在“决定对象的终值”时引用。

标准里并没有说sequence point之间只能读写一次。

比如
  1. i = i +1;
复制代码
两个sequence point 之间读了一次 i 写了一次 i ,这个表达式肯定没事呀。。。。。。。

标准里说的第二句说非常不好理解,
Furthermore, the prior value shall be accessed only to determine the value to be stored.


根据http://c-faq.com/expr/seqpoints.html上面的解释:
And that's what the second sentence says: if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written


如果对象在full expression中会被改动(写入),则这个full expression中所有对该对象的引用一定是为了“确定这个对象的最终值”。 i = i +1 就是这种情况,i 会被写入, i + 1 里面引用 i 是为了确定 i 的最终值。 a[ i ] = i ++ 就违反了这条规则(虽然没有违反第一条),a [ i ] 中对 i 的引用不是为了“确定i的终值”。

我觉得还是标准里没说清楚,“the prior value”意思显然是“对象被改动之前的值”,但我怎么知道引用的是“对象被改动之前的值”还是“对象被改动之后的值”呢? 

按照标准的意思,a[ i ] 里引用的就是 i 的“the prior value”。那 i ++ + j 里有没有引用“the prior value”呢? ++i + j 有没有引用“the prior value”呢?( a = 1) + a 里有没有引用“the prior value”呢? *p++ = 0里有没有引用“the prior value”呢?a = b = 4有没有引用“the prior value”呢?

最终还是要看“the prior value”是怎么定义的。

在C语言的设计之初,并没有严格定义求值过程,像前置++、后置++这种东西只是抽象地规定“在操作之前加一”还是“在操作之后加一”,但何为“操作”呢?

规范则严谨地定义求值过程,引入sequence point的概念后就可以保证,++肯定会在下一个sequence point前生效,至于在什么时候生效则不能确定。像 a = i ++ 按C语言最初的语义,应该是可以根据优先级来确定求值行为的,自增在赋值之后发生。标准里却认定其为“未定义”行为。如果是a[k] = i ++情况又是怎么样呢?*p++ = 0 , c [ i ++ ] = 0这种经典语句是不是“未定义”呢?它们有没有引用了“the prior value“呢?结果又绕回什么是“the prior value”的问题上来了。不过这两种情况下,按照原始C语义里的优先级来解释,显然是引用的“the prior value”,那么根据标准,它们全是未定义的。

我觉得,第一条肯定不能违反,第二条还有商量的余地。规范里的第二条基本上把++,--操作符给废掉了。像 c [ i ++ ] = 0这样的表达式,虽然是未定义行为(如果理解正确的话),编译器显然可以确定会发生什么事。 i++ + j 亦是同理。这能不能看作约定俗成的规则呢? 全世界写编译器的人大概都不会因为这种”未定义“行为而中止编译过程吧,他们对”该发生什么事“的认识也应该是统一的吧。
===================================

PS:在CU上搜到这个帖子,http://bbs.chinaunix.net/viewthread.php?tid=310576,六年前就有人解释地这么清楚了。。。。。。
作者: ypyf3000    时间: 2010-10-02 01:48
确实跟标准说的不一致呀。

标准里的第一句话说,sequence point之间对象的值只能改变一次;第二句话 ...
tempname2 发表于 2010-10-02 01:22



    i = i +1;只存在一个序点而不是两个。
作者: VIKING_nb    时间: 2010-10-02 10:07
回复 51# pmerofc

我好怕呀,现原形啦,人家都不屑于鄙视我啦!

能问出:
外部或static变量的生存期长于main()函数?
[C] 请教一个基础问题——数组名减1是否可以

这两个问题都需要问的人,还好意思说这里是幼儿园那个现原形不屑于鄙视。
作者: pmerofc    时间: 2010-10-02 11:55
提示: 作者被禁止或删除 内容自动屏蔽
作者: tempname2    时间: 2010-10-02 12:25
i = i +1;只存在一个序点而不是两个。
ypyf3000 发表于 2010-10-02 01:48


i = i + 1 没有序点。前一个分号和后一个分号可以看做序点。。。。。。
作者: ypyf3000    时间: 2010-10-02 12:36
本帖最后由 ypyf3000 于 2010-10-02 12:41 编辑
i = i + 1 没有序点。前一个分号和后一个分号可以看做序点。。。。。。
tempname2 发表于 2010-10-02 12:25



    完整表达式的末尾存在一个序点。
作者: tempname2    时间: 2010-10-02 12:39
完整表达式的末尾存在一个序点。
ypyf3000 发表于 2010-10-02 12:36


a full expression is an expression statement, or any other expression which is not a subexpression within any larger expression


full expression是表达式语句,或者是没有更上层表达式的表达式。

其实说得就是“最大的表达式”,后面那句话应该是针对if ,while里的条件说的。
作者: ypyf3000    时间: 2010-10-02 12:41
full expression是表达式语句,或者是没有更上层表达式的表达式。

其实说得就是“最大的表达式 ...
tempname2 发表于 2010-10-02 12:39



    顺便附带我从wiki上翻译的关于哪些地方存在序点的总结:
1.在&&(逻辑与),||(逻辑或)和逗号操作符的左操作数和右操作数的求值之间。
2. 在三元“问号”操作符的第一个操作数与第二个或者第三个操作数的求值之间。
3. 在一个完整表达式的末尾。这个范畴包括表达式语句(诸如赋值 a=b;),return语句,if,switch,while或者do-while等语句的条件表达式,还有for语句中的三个表达式。
4. 函数调用时,在进入函数体之前。
5. 函数返回时,在返回值被拷贝到调用上下文之后。
6. 在初始化式的末尾。
作者: tempname2    时间: 2010-10-02 12:59
顺便附带我从wiki上翻译的关于哪些地方存在序点的总结:
1.在&&(逻辑与),||(逻辑或)和逗号 ...
ypyf3000 发表于 2010-10-02 12:41


C-faq上的说明:
full expression
    The complete expression that forms an expression statement, or one of the controlling expressions of an if, switch, while, for, or do/while statement, or the expression in an initializer or a return statement. A full expression is not part of a larger expression. (See ANSI Sec. 3.6 or ISO Sec. 6.6.)


C99 6.9里面:
Afull expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if or switch); the
controlling expression of a while or do statement; each of the (optional) expressions of
a for statement; the (optional) expression in a return statement. The end of a full
expression is a sequence point.


里面都强调了,full expression 的一个特征是“is not part of another expression”。

你在Wiki上引用的是不是C++对顺序点的定义啊。。。。。。。
作者: ypyf3000    时间: 2010-10-02 13:21
C-faq上的说明:


C99 6.9里面:


里面都强调了,full expression 的一个特征是“is not part  ...
tempname2 发表于 2010-10-02 12:59



    原文说,除了倒数第二条C语言没有明文规定,只是暗含的。
作者: ypyf3000    时间: 2010-10-02 13:25
C-faq上的说明:


C99 6.9里面:


里面都强调了,full expression 的一个特征是“is not part  ...
tempname2 发表于 2010-10-02 12:59



    其实我们说的是一个意思。
作者: tempname2    时间: 2010-10-02 13:29
原文说,除了倒数第二条C语言没有明文规定,只是暗含的。
ypyf3000 发表于 2010-10-02 13:21



我又看了一下你刚才的发言,好像是你理解错了。

你引用的Wiki里写到“在一个完整表达式的末尾。这个范畴包括表达式语句(诸如赋值 a=b;)”,它举的第一个完整表达式的例子是“表达式语句”,但是解释“表达式语句”时又举的“赋值语句”的例子。或许你是把“赋值语句”和“赋值表达式”搞混了吧。

但就算如此, i = i + 1里也没有顺序点呀。。。。。。
作者: ypyf3000    时间: 2010-10-02 13:35
我又看了一下你刚才的发言,好像是你理解错了。

你引用的Wiki里写到“在一个完整表达式的末尾。这 ...
tempname2 发表于 2010-10-02 13:29



    请注意分号!如果这里没有序点,那估计我们写的代码到处都是未定义了。
作者: tempname2    时间: 2010-10-02 13:41
请注意分号!如果这里没有序点,那估计我们写的代码到处都是未定义了。
ypyf3000 发表于 2010-10-02 13:35



我知道,我的意思是 i = i + 1; 里的 " i = i + 1"中没有顺序点。

之前我以为你说“赋值表达式”末尾也有顺序点,那样有些例子的情况就不一样了,但上面的例子不受影响。
作者: ypyf3000    时间: 2010-10-02 13:42
我知道,我的意思是 i = i + 1; 里的 " i = i + 1"中没有顺序点。

之前我以为你说“赋值表达式”末 ...
tempname2 发表于 2010-10-02 13:41



    呵呵 ,那就对了。
作者: 幻の上帝    时间: 2010-10-02 15:08
本帖最后由 幻の上帝 于 2010-10-02 15:11 编辑
我觉得程序员恰恰应该摆脱“按一般的人类的思维”
如果是写code,必须事先知道自己要写什么
如果是读code,正确的方式应该是编译器方式。因为程序设计语言不是自然语言,而是一种严格的形式语言

至于您说的多线程,我还没想通您想表达的是什么意思。能否麻烦更具体地说说么
KBTiller 发表于 2010-09-30 20:53


很遗憾,摆脱“按一般的人类的思维”做不到。
首先,“事先知道自己要写什么”,就是纯粹的人类的思维。
其次,总是完全按编译器方式读code也是不现实的,效率太低。至少目前为止应该还没有证据表明人脑有底层的机制来帮助保证正确地执行大量重复的操作。如果不经过刻意的训练,恐怕光是在阅读代码中区分语法和语义问题就很困难了。通常读起来不对劲的代码,往往是直觉先于理性,要经过延迟才能判断出到底是哪里有问题(因为延迟时间很短,所以实用上问题不大;相比之下,这种非形式化的借助直觉的方法倒更不容易出错)。而这种习惯是学习语言的时候养成的(注意学习语言的手段不可能是严格形式化的,首先语言之外现实的语义的存在就阻碍这点——例如“内存”),所以很难改变。
关于“多线程”:人的大脑分为若干个神经中枢,其中的一些是在许多环境下可以协同工作,也就是物理上的一心多用。在此之上,对于使用到相同资源(神经中枢)的任务,做到这点比较困难,但也不是无法实现。与此相关的是,一般顺序地阅读代码时,除去I/O,可以同时分析代码的语法和语义——例如一行语法上有错误的代码,有经验的程序员可能在发现错误的同时就可以猜测出大致要表达什么(尽管不是他写的),而这两种行为并不一定具有严格的先后关系(应该和具体的人相关)。这点在直觉上应该很容易验证,虽然其机制并不明确。

总之,关于代码的验证,总体上编译器永远比人可靠。人要达到编译器相同的可靠性,代价是损失本来就不高的解析效率到不现实的地步。花费大量的时间和精力纠结严格形式化的方法有害于非形式化语义的理解(注意这点是编译器无法做到的),得不偿失。
作者: KBTiller    时间: 2010-10-02 20:53
回复 78# 幻の上帝


    谢谢回复
    看来我们的分歧是,您认为摆脱“按一般的人类的思维”做不到,而我觉得摆脱“按一般的人类的思维”应该能通过训练实现。事实上我觉得这恰恰是程序员应该必备的职业素质和职业技能之一
作者: EvanChueng    时间: 2010-10-04 20:02
建议加括号,没必要考究这种优先级的问题,除非自己写编译器
作者: 倒数第二位    时间: 2010-10-05 21:23
回复 8# CountOnMyself


    我弱弱的问问,i+++j,编译器怎么知道是++,+。
这个用运算符优先级的说话有点说不过去,倒是很多人说贪心,编译器在做词法分析时贪心处理,导致这种结果倒还是有一定道理
  个人见解
作者: Esakyo    时间: 2010-10-06 10:35
唉,都是编译器惹得祸!
作者: shuge_guet    时间: 2010-10-06 20:33
贪心法使之!
作者: asker160    时间: 2010-10-06 23:14
各位高手:

这个加号的拆分,究竟发生在哪个阶段?

1. 词法分析
2. 语法分析
3. 语义分析

怎么前面各位高人给出的答案都不一样呢?
谢谢
作者: cobras    时间: 2010-10-06 23:16
运算符有个运行优先级和结合优先级.其中的给合优先级在编译阶段起作用,运行优先级在运行阶段起作用.
作者: pmerofc    时间: 2010-10-06 23:28
提示: 作者被禁止或删除 内容自动屏蔽
作者: jiqiren007    时间: 2010-10-07 11:23
刚看到c traps 里面有讲
作者: whyliyi    时间: 2010-10-07 16:35
恩,贪心算法,是这样的
作者: asker160    时间: 2010-10-08 11:53
各位高手:

这个加号的拆分,究竟发生在哪个阶段?

1. 词法分析
2. 语法分析
3. 语义分析

怎么前面 ...
asker160 发表于 2010-10-06 23:14


      有大侠回答一下这个问题么? 前面各位高人讨论的结果都不一样啊。
作者: davelv    时间: 2010-10-08 11:58
各位高手:

这个加号的拆分,究竟发生在哪个阶段?

1. 词法分析
2. 语法分析
3. 语义分析

怎么前面 ...
asker160 发表于 2010-10-06 23:14


我的理解是词法。
作者: pmerofc    时间: 2010-10-08 16:41
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2