[科普]随便提个问,关于某个表达式

FrankHB1989 2013-01-13 10:53:58
似乎从来没散过分……
问题:
已知a和b是C++源代码(代码的其它部分都保证正确)中已经合法声明、无歧义的标识符,作为表达式具有相同的非const对象类型。
指出表达式 a ^= b ^= a ^= b 有问题的地方。
要求完整地讨论各种情况,给出充分理由,最好有权威依据;不讨论具体语言实现。
坑点应该超出大部分人想象。提示反白可见:

1.undefined behavior
2.types
3.identical lvalue or not
4.language linkage
5.C++11
6.full-expression or not

...全文
1042 73 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
73 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2014-04-22
  • 打赏
  • 举报
回复
另外,这些不同标准,对应哪些主流编译器的哪些版本,有谁能列出来.
lm_whales 2014-04-22
  • 打赏
  • 举报
回复
你对标准把握的真好,好牛地说
FrankHB1989 2014-04-21
  • 打赏
  • 举报
回复
引用 69 楼 lm_whales 的回复:
敢问作为表达式具有相同的非const对象类型,这一说法。 有没有排除 int a = 10; int &b = a; 这种情况。 另外如果operator ^() 被重载,能否保证,语义正确,是否还表示两个整数之间的 异或 操作。
这个是排除了。b是引用类型,不是对象类型。 嘛, #define b f() f可以返回一个类类型非const对象,配合重载仍然可以没问题。
FrankHB1989 2014-04-21
  • 打赏
  • 举报
回复
引用 53 楼 HelloElite 的回复:
什么时候会公布答案吗 - -! 表示还是完全不懂,跑进来看一次头疼一次。好像跟课本上的东西完全没关系,看来看去还是只知道那个表达式的运算顺序和结果 楼主想说的是什么求教真心求教
不好意思,本来打算坑一个月,没注意结贴率的习惯,要不是挖起来还真给忘了- -。
引用 57 楼 pengjialaosan 的回复:
置顶的那个帖子大概是为了一次性回答那些问 i++ ++i之类蛋疼问题。大家都知道在写程序的时候要避免写这种表达式,但依然有学校考这个,依然有人问。至于是不是过时,那要看什么时候没有人再问i++ ++i这种蛋疼问题。
再说明确点吧。 那篇置顶的过时是指解释上。ISO C++11已经没有sequence point这种说法了,尽管ISO C11仍然保留。 提示分析/答案: 1.UB(undefined behavior) 这是坑的核心。 除非显式另行约定(例如在特定环境下使用特定的扩展),只要ISO C++约定存在UB,整个程序的行为无法保证可预测,就是一般意义上的错误的C++代码。 最明显的直接的UB是C++98/03的同一个对象在两个序列点(sequence point)之间修改超过一次。^=没保证有序列点,所以这里就中招了。 C++11移除了序列点这个说法,对应为在同一个对象上存在无序(unsequenced)的不同副作用时UB。但是,这里没有因此UB。这点下面详细说。 2.类型 (1)用户自定义的类类型可以重载。重载的操作符使用和内建操作符不同的规则。内建操作符导致的UB,被重载了以后就未必。 (2)volatile左值的读也是副作用……就算^=不引起副作用,这里也可能因此UB。 3.有个言语上的陷阱,宏名跟对象名显然不是一个范畴的东西,但这里都是“标识符”。 #define a f() //你能保证两个a是同个对象么…… 如果这个前提不存在,自然不会因此UB了。 (嘛,我可没说这代码就是用来干嘛的……) 4.language linkage——这个可以认为是启发也可以认为是混淆视线的。 这里强调过了是C++源代码。 extern "C"中的代码的确使用跟其它C++代码不一样的规则,但不包括这里是否有UB。除了禁止定义namespace作死之类,还是使用C++规则。 话说回来,C跟C++98/03在这里大体一致,不过C++11嘛…… 5.C++11。简单来说,比起C++98/03,^=在这里有附加的保证有序(sequenced),所以没有上面指出的UB。 a ^= b^= a^= b 可以就照还没入门者的直觉“从右到左执行”。当然,原因解释起来就麻烦了。 详细坑比较深:http://tieba.baidu.com/p/2091426198(PS.这篇不够明确C11的问题。这点C11还是跟C89/C99/C++98/C++03一样UB。) 6.因为a ^= b ^= a ^= b是左值,于是不管表达式内有没有直接引起UB,随便可以搞成UB……比如(a ^= b ^= a ^= b)++。 因为发生修改在这个表达式内也有份,所以逃不了干系。 嘛,算是个小陷阱,no zuo no die。
lm_whales 2014-04-11
  • 打赏
  • 举报
回复
敢问作为表达式具有相同的非const对象类型,这一说法。 有没有排除 int a = 10; int &b = a; 这种情况。 另外如果operator ^() 被重载,能否保证,语义正确,是否还表示两个整数之间的 异或 操作。
「已注销」 2014-04-11
  • 打赏
  • 举报
回复
楼主艺高人胆大啊
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 49 楼 HelloElite 的回复:
是要说明c++只是提供一个规范所以移植性很糟糕吗? 虽然不明白楼主拿出这个想说明什么,也不认为这是炫技的东西,但是很反感楼主的语气,什么管管教化,稍微负责下这类的话听着很刺耳。
是C/C++的设计很糟糕(也导致标准维护起来很困难——这对大多数用户倒不见得要关心)但确实在一定程度上无法避免(Java/C#在这里采取其它策略,但付出了优化潜力的代价)。这导致只能提高对用户的要求。如果一个C/C++用户对于这种程度的例子连一个问题都看不出来,也腾不出时间了解这里的基本问题,那么他最好放弃继续折腾C/C++,否则以后很可能浪费更多时间。
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 48 楼 HayYoung 的回复:
引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB1989 的回复:果然今非昔比……不说知不知道UB了,指出求值顺序、重载的都没几个?还是知道自己没把握所以干脆简单的也不说了? @supermegaboy 不管管……
好吧,我先填半个坑。你的理解按C++11的确是没错的。 但是,按C++98/03,你的理解和你引用的这段话是错的。而且,这里根本没提到UB。 C++11对赋值表达式新增了约束规则,取消了这种情况下反直觉的UB。
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
a^=(b^= (a^= b))和a^= b^= a^= b一样。莫非你以为a^= b^= a^= b是((a^= b)^= a)^= b?
HayYoung 2013-01-17
  • 打赏
  • 举报
回复
引用 55 楼 FrankHB1989 的回复:
引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB1989 的回复:果然今非昔比………
搜出来的资料不少,第三个或许是我看漏了,总感觉解释得不怎么清楚。如果能想bs的书上那么解释的清楚就好了。举个例:int i = 1; v[i] = i++; 这里可能是v[1] = 1,或 v[2] = 1,这种就是我说的ub,;我的问题其实和第三个差不多。问下楼主,那么你认为这个a^=(b^= (a^= b))是否是ub?我们先讨论这个,然后再讨论a^= b^= a^= b。
彭家老三 2013-01-17
  • 打赏
  • 举报
回复
在codeblock中将代码改成下面这样
int main()
{
    int a =0;
    int b =21;
    a^=b^=a^=b;
    cout<<a<<" "<<b<<endl;

	return 0;
}
结果是对的,但编译的时候会提示: warning: operation on 'a' may be undefined|
彭家老三 2013-01-17
  • 打赏
  • 举报
回复
引用 63 楼 FrankHB1989 的回复:
引用 62 楼 pengjialaosan 的回复: 引用 60 楼 pengjialaosan 的回复:引用 56 楼 FrankHB1989 的回复: 引用 55 楼 FrankHB1989 的回复: 引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 4……
编译器是g++
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 62 楼 pengjialaosan 的回复:
引用 60 楼 pengjialaosan 的回复:引用 56 楼 FrankHB1989 的回复: 引用 55 楼 FrankHB1989 的回复: 引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回……
C::B只是IDE,可以换编译器。大概你用MinGW?
彭家老三 2013-01-17
  • 打赏
  • 举报
回复
引用 60 楼 pengjialaosan 的回复:
引用 56 楼 FrankHB1989 的回复: 引用 55 楼 FrankHB1989 的回复: 引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYo……
然后又用VS2008,也没有问题。但是用codeblock,就有问题了,显示 0 7.
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 60 楼 pengjialaosan 的回复:
引用 56 楼 FrankHB1989 的回复:引用 55 楼 FrankHB1989 的回复: 引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用……
UB表示在可移植的语言层次上不考虑可预测的行为。所以对了你只能是侥幸,或者不应该当作C++代码而只是当成C++ Builder 6.0支持的具体方言(但是我怀疑即便是集体实现的具体版本也不会保证关于这个UB的行为可以预测)。
彭家老三 2013-01-17
  • 打赏
  • 举报
回复
引用 56 楼 FrankHB1989 的回复:
引用 55 楼 FrankHB1989 的回复: 引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB198……
奇怪,我看了楼主给的链接,然后用同样的程序得到的结果是正确的。我用的IDE是C++builder6.0
int main(int argc, char* argv[])
{
    int a[] = {7,21};
    a[0]^=a[1]^=a[0]^=a[1];
    cout<<a[0]<<" "<<a[1]<<endl;
    getchar();
    return 0;
}
结果是: 21 7
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 54 楼 HayYoung 的回复:
引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB1989 的回复:果然今非昔比……不说知不知道UB了,指出求值顺序、重载的……
你看来认为*是一定有副作用了?不要忽略赋值会对象修改存储的值,这一定是副作用。而*或lvalue-to-rvalue conversion则只是有可能是副作用。 (算了,我再拆穿关于“类型”的另外半个坑好了:读volatile类型的左值是副作用。)
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 57 楼 pengjialaosan 的回复:
置顶的那个帖子大概是为了一次性回答那些问 i++ ++i之类蛋疼问题。大家都知道在写程序的时候要避免写这种表达式,但依然有学校考这个,依然有人问。至于是不是过时,那要看什么时候没有人再问i++ ++i这种蛋疼问题。
现在来看置顶的那个远没有一次性解释清楚,尤其那个主题发布没过几天就不适合正式的说法了,所以忍不住吐槽……
彭家老三 2013-01-17
  • 打赏
  • 举报
回复
置顶的那个帖子大概是为了一次性回答那些问 i++ ++i之类蛋疼问题。大家都知道在写程序的时候要避免写这种表达式,但依然有学校考这个,依然有人问。至于是不是过时,那要看什么时候没有人再问i++ ++i这种蛋疼问题。
FrankHB1989 2013-01-17
  • 打赏
  • 举报
回复
引用 55 楼 FrankHB1989 的回复:
引用 54 楼 HayYoung 的回复:引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB1989 的回复:果然今非昔比………
引用 54 楼 HayYoung 的回复:
引用 52 楼 FrankHB1989 的回复:引用 48 楼 HayYoung 的回复:引用 47 楼 FrankHB1989 的回复:引用 45 楼 HayYoung 的回复:引用 44 楼 FrankHB1989 的回复:引用 42 楼 HayYoung 的回复:引用 37 楼 FrankHB1989 的回复:果然今非昔比……不说知不知道UB了,指出求值顺序、重载的……
好吧,还有更直接的: http://stackoverflow.com/questions/9958514/sequence-point-xor-swap-on-array-get-wrong-result
加载更多回复(53)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧