我通常不会编写C++代码,但我的一个奇怪的comp sci朋友厌倦了查看我精彩的FORTRAN程序并挑战我用C++重写其中一个,因为他更喜欢我的C++代码.(我们在这里投入资金.)确切的术语是它需要在现代C++编译器中进行编译.也许他讨厌一个好的conio.h - 我不知道.
现在我意识到在C++中有很好的写作方式,但是我想通过尽可能使我的C++版本成为FORTRAN-esque来获得个人胜利.对于奖励积分,当我转换代码时,这可能会节省一些时间和精力.
所以!这带我进入以下相关查询:
在gotos:
在longjmp上:
现在我的主要关注点是为此计算goto.看起来我可能会使用longjmp来完成这项工作,因为void指针数组不是C++标准的一部分,而是GCC特定的扩展.
我读了几个关于未定义行为和序列点的非常好的答案(例如未定义的行为和序列点),我明白了
int i = 1;
a = i + i++; //this is undefined behaviour
Run Code Online (Sandbox Code Playgroud)
根据C++标准,是未定义的代码.但是,未定义的行为背后的深层原因是什么?是否足以使其成为未指明的行为?正常的论点是,通过几个序列点,C++编译器可以更好地针对不同的体系结构进行优化,但是不会让它未指定允许这些优化吗?在
a = foo(bar(1), bar(2)); //this is unspecified behaviour
Run Code Online (Sandbox Code Playgroud)
编译器也可以优化,并且它不是未定义的行为.在第一个例子中,似乎很清楚,a是2或3,所以语义似乎对我来说很清楚.我希望有一个推理,为什么有些东西是未指定的,有些是未定义的.
我知道这看起来很熟悉但是在微软招募实习生的测试中,这是一个问题.在我看来,这y=++y不符合标准,但我认为可能更好(确定我比那些在MS上编写这些测试的人更好).所以我问你的建议.您认为这样的表达式是否符合标准并且不会导致未定义的行为?
#include <stdio.h>
int main(){
int a = 10;
int b = 10;
a = ++a; //What ???
b = b++; //What ???
printf("%d %d\n",a,b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc用来编译时抱怨它-Wsequence-point.(没有明确说明它是否是C或C++特定问题.)
但只提供了四个答案:
a) 10 10
b) 11 10
c) 10 11
d) 11 11
Run Code Online (Sandbox Code Playgroud)
虽然一个人不仅限于选择一个答案(所以也许我应该选择全部四个?)
嗯,在我看来,在自我递增和分配之间没有序列点.所以这违反了规范.不是吗?
这样定义,我们既不做++x++也不做++x--.但另一方面,无论是(++x)++和(++x)--是有用的表达式:(++x)++增量x由两个并返回"中间"的价值,而(++x)--实质上等同于x+1而是完全避免了打电话operator+,这是非常有用的时候.
那么为什么没有定义的优先级++x++自动扩展到(++x)++而不是++(x++)?对于后者有一些隐藏的含义,我不明白,或者只是将优先级保持为一个简单的列表,所有前缀运算符组成一个单一的级别?
编辑好的,我没有明确说出来,但是:当然我的意思x是用户定义的类型.对于内置类型,(x+=2)-1当然比更好的(++x)++,并且x+1是一个很多好过(++x)--.我想到的情况是一个相当复杂的半关联容器的迭代器,其中运算符+=和+(为随机访问而设计)必须重建缓存才能有效地处理一般请求,因此是一个命令比...慢++.但是我当然可以将它们修改为总是首先检查参数是否是一个非常小的整数,并且在这种情况下只是operator++反复调用而不是执行随机访问过程.这应该可以正常工作,虽然我可以想象我可能在某种程度上有一种情况,我想operator+=总是采用随机访问方式,无论我呈现的数字有多少.
具有简单的和精心memorizeable优先列表,其中的优点所有之前来后缀运算符任何前缀运营商足以容忍的总是不必使用括号来构成前和后缀运算符的小缺点
++/--,因为该组合物是非常少用.
更简单的"C就是这样做的",虽然看起来可能是真正的原因,但对我来说远不那么令人满意,因为C中++x++根本不允许这样做,所以可以重新定义这个非常复杂的构图而不会损坏任何构图.现有代码.
无论如何,我会继续使用(++x)--,因为括号真的没有那么多伤害.
c++ increment operator-precedence prefix-operator postfix-operator
C11标准(ISO/IEC 9899:2011)在表达式中引入了新的副作用测序定义(参见相关问题).该序列点概念已经补充了之前测序和后序关系,这是现在所有定义的基础.
第6.5节"表达式",第2点说:
如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义.如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的.
稍后,第6.5.16节"分配操作员",第3点指出:
在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序.对操作数的评估是不确定的.
第一个引用的段落(6.5/2)由两个例子支持(与C99标准相同):
a[i++] = i; //! undefined
a[i] = i; // allowed
Run Code Online (Sandbox Code Playgroud)
这可以通过以下定义轻松解释:
因此,i++(LHS)的副作用与i(RHS)无关,这给出了不确定的行为.
i = ++i + 1; //! undefined
i = i + 1; // allowed
Run Code Online (Sandbox Code Playgroud)
但是,此代码似乎在两种情况下都会导致定义的行为:
因此,执行++i + 1
应该在更新的副作用之前i,这意味着相对于对同一标量对象的不同副作用或使用相同标量的值的值计算,对未标测的标量对象没有副作用宾语.
使用C99标准提出的术语和定义很容易解释这些例子(参见相关问题).但i = ++i + 1根据C11的术语,为什么不明确?
在过去一周左右的时间里,我一直在阅读严格的别名规则并进入本文:了解C/C++严格别名.
本文通过几种方式将两个交换32位整数的两半进行交换,给出了良好的示例和违反严格别名规则的示例.但是,我无法理解其中一个例子.
此代码被描述为已损坏.
uint32_t
swaphalves(uint32_t a)
{
a = (a >> 16) | (a << 16);
return a;
}
Run Code Online (Sandbox Code Playgroud)
给出的理由是:
这个版本看起来很合理,但你不知道|的左右两侧 将各自获得原始版本,
a或者如果其中一个将获得另一个的结果.这里没有序列点,因此我们对此处的操作顺序一无所知,并且您可能会使用不同级别的优化从同一编译器获得不同的结果.
我不同意.这段代码对我来说很好看.a在该a = (a >> 16 | (a << 16);行中只有一个写入,我希望a在写入之前进行两次读取.此外,没有指针或引用,也没有不兼容的类型.
我在此代码中是否缺少严格的别名冲突,或者文章是否不正确?
我在这里读到有一个序列点:
在与输入/输出转换格式说明符相关联的操作之后.例如,在表达式中
printf("foo %n %d", &a, 42),%n在打印之前评估之后有一个序列点42.
但是,当我运行此代码时:
int your_function(int a, int b) {
return a - b;
}
int main(void) {
int i = 10;
printf("%d - %d - %d\n", i, your_function(++i, ++i), i);
}
Run Code Online (Sandbox Code Playgroud)
而不是我期望得到的:
12 - 0 - 12
这意味着没有为转换格式说明符创建序列点.http://en.wikipedia.org是错误的,还是我只是误解了某些内容,或者在这种情况下gcc是否不合规(顺便提一下Visual Studio 2015会产生相同的意外结果)?
编辑:
我理解,参数your_function的评估顺序和分配给参数的顺序是未定义的.我不是在问我为什么我的中期是0.我在问为什么其他两个术语都是12.
阅读本主题后,我仍然感到有些困惑.以下C++表达式是否*d++ = ~(*d);定义良好?是的,我知道像这样的复合表达是丑陋的......我没有写它.
当我将它与以下内容进行比较时,我发现生成的程序集略有不同:
*d = ~(*d);
d++;
Run Code Online (Sandbox Code Playgroud)
部件:
*d++ = ~(*d);
0x83384 LDR R3,[R0 <d>,4] <<diff
0x83388 ADD R1 <c>, R1 <c>, 1
0x8338c MVN R3, R3
0x83390 STR R3,[R0 <d>],4
Run Code Online (Sandbox Code Playgroud)
VS
*d = ~(*d);
d++;
0x83384 LDR R3,[R0 <d>]
0x83388 ADD R1 <c>, R1 <c>, 1
0x8338c MVN R3, R3
0x83390 STR R3,[R0 <d>],4
Run Code Online (Sandbox Code Playgroud)
谢谢!
如果我做:
std::map<string, size_t> word_count;
size_t value = word_count.count("a") == 0 ? 1 : 2;
word_count["a"] = value;
Run Code Online (Sandbox Code Playgroud)
那么word_count ["a"]的最终值是1,正如我所料.如果相反,我做:
std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)
那么word_count ["a"]的最终值是2.为什么!?
我知道写点东西
++a = a++;
Run Code Online (Sandbox Code Playgroud)
不仅是不可读的,而且还违反了c/c ++序列点.
这些限制来自哪里?在将它们视为错误之前,如何才能看到这些"问题"?