更新,见下文!
我听说并读过C++ 0x允许编译器为以下代码段打印"Hello"
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它显然与线程和优化功能有关.在我看来,这可能让许多人感到惊讶.
有人能够很好地解释为什么必须允许这样做吗?作为参考,最新的C++ 0x草案说明了6.5/5
在for语句的情况下,在for-init语句之外的循环,
- 不调用库I/O函数,和
- 不访问或修改易失性对象,以及
- 不执行同步操作(1.10)或原子操作(第29条)
可以通过实现来假设终止.[注意:这是为了允许编译器转换,例如删除空循环,即使无法证明终止也是如此. - 结束说明]
编辑:
这篇富有洞察力的文章谈到了标准文本
不幸的是,没有使用"未定义的行为".但是,只要标准说"编译器可以假设P",就暗示具有非-P属性的程序具有未定义的语义.
这是正确的,是否允许编译器为上述程序打印"Bye"?
这里有一个更有见地的线索,这是关于C的类似改变,由Guy完成上述链接文章开始.在其他有用的事实中,他们提出了一个似乎也适用于C++ 0x的解决方案(更新:这将不再适用于n3225 - 见下文!)
endless:
goto endless;
Run Code Online (Sandbox Code Playgroud)
看来,编译器不允许优化它,因为它不是循环,而是跳转.另一个人总结了C++ 0x和C201X的建议更改
通过编写一个循环,程序员断言或者环路不可见的东西的行为(执行I/O,访问volatile对象,或执行同步或原子操作), 或者,它最终会终止.如果我通过编写一个没有副作用的无限循环来违反这个假设,我对编译器撒谎,而我的程序的行为是未定义的.(如果我很幸运,编译器可能会警告我.)语言不提供(不再提供?)表达无可见行为的无限循环的方法.
2011年3月3日更新为n3225:委员会将案文移至1.10/24并说
实现可以假定任何线程最终将执行以下操作之一:
- 终止,
- 调用库I/O函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作.
的goto把戏,不工作了!
当我用g ++编译下面的简单递归代码时,汇编代码只返回i,好像g ++可以像人类那样做一些代数技巧.
int Identity(int i) {
if (i == 1)
return 1;
else
return Identity(i-1)+1;
}
Run Code Online (Sandbox Code Playgroud)
我不认为这种优化是关于尾递归的,显然,g ++必须至少做这两件事:
如何重现
% g++ -v
gcc version 8.2.1 20181127 (GCC)
% g++ a.cpp -c -O2 && objdump -d a.o
Disassembly of section .text:
0000000000000000 <_Z8Identityi>:
0: 89 f8 mov %edi,%eax
2: c3
Run Code Online (Sandbox Code Playgroud)
更新: 感谢很多人回答这个问题.我在这里收集了一些讨论和更新.
更新+回答: 感谢下面的答案(我已经标记它有用,并且还检查了manlio的答案),我想我理解编译器如何以简单的方式完成此操作.请参阅下面的示例.首先,现代gcc可以做一些比尾递归更强大的东西,所以代码转换成这样的东西:
// Equivalent to return i
int Identity_v2(int i) {
int ans = 0;
for (int …Run Code Online (Sandbox Code Playgroud) 给定具有无限递归的C程序:
int main() {
main();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么会导致堆栈溢出.我知道这导致C++中来自以下线程的未定义行为这是无限递归UB吗?(并且作为无法main()在C++中调用的副节点).但是,valgrind告诉我这会导致堆栈溢出:
Stack overflow in thread 1: can't grow stack to 0x7fe801ff8
Run Code Online (Sandbox Code Playgroud)
最后由于分段错误,程序结束:
==2907== Process terminating with default action of signal 11 (SIGSEGV)
==2907== Access not within mapped region at address 0x7FE801FF0
Run Code Online (Sandbox Code Playgroud)
这是C中的未定义行为,还是应该导致堆栈溢出,为什么会导致堆栈溢出?
编辑
1我想知道C中是否允许无限递归?
2这是否会导致堆栈溢出?(已经得到了充分的回答)
具有空体的无限循环在C++ 11中具有未定义的行为.我不知道它是否也用C语言,所以让我说我在C++ 11中编写嵌入式固件(我知道,不太可能,但请耐心等待).
如果我main只是一个:
while (true) {}
Run Code Online (Sandbox Code Playgroud)
并且设备的其余功能由中断处理,我可以采取哪些方法来发现我的实现是否使这个循环安全且有意义?请记住,根据标准,在这种情况下,实现可以随意执行任何操作,包括完全删除循环.
假设在实现的文档中没有明确说明,因为我从未见过它.
或者这是一个失败的原因,我应该破解一个解决方法?
volatile unsigned int dummy = 0;
while (true) {
// Make the loop well-defined...
dummy++;
// ...with a trivial operation that'll hardly ever even happen
sleep(42*86400);
}
Run Code Online (Sandbox Code Playgroud)
我认识到嵌入式开发人员在历史上并没有过多地考虑这种事情,而是从他们的编译器中采用更"脚踏实地","常识"的方法.但我更倾向于严格按照标准编码,以尽可能避免意外.
我有一个线段列表(std::vector<std::pair<int, int> >我想对其进行迭代和细分。该算法将以psuedocode表示:
for segment in vectorOfSegments:
firstPoint = segment.first;
secondPoint = segment.second;
newMidPoint = (firstPoint + secondPoint) / 2.0
vectorOfSegments.remove(segment);
vectorOfSegments.push_back(std::make_pair(firstPoint, newMidPoint));
vectorOfSegments.push_back(std::make_pair(newMidPoint, secondPoint));
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是如何push_back在不永久遍历此列表的情况下如何添加新元素(并删除旧元素)。
似乎最好的方法可能是首先创建此向量的副本,然后将该副本用作参考,clear()原始向量,然后push_back将新元素用作最近清空的向量。
有更好的方法吗?
注意!
我显然没有向这里的每个人清楚地表明我的观点,这令人非常沮丧.我的目标是打消那种
volatile实际上是无操作的神话,它什么都不做.我并没有试图说它应该被使用,它是必不可少的,它不是多余的,等等.我已经表明
volatile它仍然可以做一件事.我承认在某些情况下它是多余的,并且多线程示例是一个糟糕的选择.我也没有试图隐瞒我的答案的初始修订包含错误这一事实.但这个Q&A甚至没有达到其预期目的.为此,我认为是时候把它扔掉了.
感谢Kerrek和TC的见解.我只是不认为他们的回答符合我想问的问题.我很确定这是我的错,因为它很糟糕.
所以我放弃了!并将其作为问题的副本而不是它的意图,但它被解释为.
干杯! (&hth.)
我正在写一个线程中的变量并在另一个线程中读取它.我被告知这对我volatile来说完全无用,除非我正在使用硬件,否则我不需要在这个时代使用它.
int x = 0;
void thread1()
{
while (true) {
sleep(1);
if (x > 0)
break;
}
}
void thread2()
{
while (true) {
sleep(1);
x++;
}
}
Run Code Online (Sandbox Code Playgroud)
volatile在这种情况下,我可以获得任何收益吗?
如果x不是一个简单int的类而是一个类类型怎么样?
最近有人试图说服我cppreference是错误的,因为它说没有副作用的无限循环将是未定义的行为。与无限循环是否未定义相关的一个问题是无限循环与无限递归。两者都是未定义的吗?。接受的答案引用了标准并得出结论:是的,没有副作用的无限循环是未定义的行为。
其他相关问题有:
相关引用是([basic.progress]p1):
该实现可能假设任何线程最终都会执行以下操作之一:
- 终止,
- 调用库 I/O 函数,
- 通过易失性左值执行访问,或者
- 执行同步操作或原子操作。
当标准说“实现可能假设 X”时,这种措辞是否意味着包含“非 X”的代码未定义?
(在这个例子中,这意味着egfor (;;);是未定义的,但我很好奇该措辞的一般含义)
考虑以下这个机构main:
std::srand(std::time(nullptr));
while (std::rand());
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,我无法找到任何内容,无论是在规范中,谷歌上,还是在本网站上,都是关于它是否定义明确.至于规格:
N3485§6.5/ 4 [stmt.iter]对此情况说:
[注意:迭代语句中对条件的要求在6.4中描述. - 结束说明]
但是,通过6.4,我没有看到任何涉及这种情况的东西.理论上,循环可以实际上永远持续下去,但在实践中,我通常有5毫秒的运行时间,所有测试运行中有一次是22毫秒.
将循环终止条件作为变化的(伪)随机数的基础是明确定义的行为吗?如果不是,那是什么行为?
#include <iostream>
int foo(int i){
return foo(i + 1);
}
int main(int argc,char * argv[]){
if(argc != 2){
return 1;
}
std::cout << foo(std::atoi(argv[1])) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
%clang ++ -O2 test.cc
%time./ a.out 42
1490723512
./a.out 42 0.00s用户0.00s系统69%cpu 0.004总计
%time./ a.out 42
1564058296
./a.out 42 0.00s用户0.00s系统56%cpu 0.006总计
%g ++ -O2 test.cc
%./ a.out 42 #infinte递归
^ C
% clang++ --version
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-apple-darwin12.4.0
Thread model: posix
% g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build …Run Code Online (Sandbox Code Playgroud) #include "stdafx.h"
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
//this program will let the user input their assignment score and see their letter grade
int main() {
int score;
cout << "Input your score: ";
//to make the while loop
int x = 1;
while (x == 1) {
cin >> score;
if (score >= 90){
cout << "\nA";
break;
}
else if (score >= 80) {
cout << "\nB";
break;
}
else if …Run Code Online (Sandbox Code Playgroud)