相关疑难解决方法(0)

优化"while(1);" 在C++ 0x中

更新,见下文!

我听说并读过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把戏,工作了!

c++ optimization loops c++11

150
推荐指数
5
解决办法
1万
查看次数

现代编译器优化如何将递归转换为返回常量?

当我用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 ++必须至少做这两件事:

  1. 如果我们传递一个负值,这个代码将落入一个无限循环,那么g ++是否有效消除这个错误呢?
  2. 虽然可以枚举从1到INT_MAX的所有值,然后g ++可以告诉该函数将返回i,显然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)

更新: 感谢很多人回答这个问题.我在这里收集了一些讨论和更新.

  1. 编译器使用某种方法来知道传递负值会导致UB.也许编译器使用相同的方法来进行代数技巧.
  2. 关于尾递归:根据维基百科,我以前的代码不是尾递归形式.我尝试了尾递归版本,gcc生成了正确的while循环.但是,它不能像我以前的代码那样返回i.
  3. 有人指出编译器可能试图"证明"f(x)= x,但我仍然不知道所用实际优化技术的名称.我对这种优化的确切名称感兴趣,例如常见的子表达式消除(CSE)或它们的某种组合或其他.

更新+回答: 感谢下面的答案(我已经标记它有用,并且还检查了manlio的答案),我想我理解编译器如何以简单的方式完成此操作.请参阅下面的示例.首先,现代gcc可以做一些比尾递归更强大的东西,所以代码转换成这样的东西:

// Equivalent to return i
int Identity_v2(int i) {
  int ans = 0;
  for (int …
Run Code Online (Sandbox Code Playgroud)

c++ recursion gcc g++ compiler-optimization

15
推荐指数
1
解决办法
765
查看次数

C中的无限递归

给定具有无限递归的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 recursion

13
推荐指数
3
解决办法
1万
查看次数

确定空无限循环的编译器行为的最佳方法是什么?

具有空体的无限循环在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)

我认识到嵌入式开发人员在历史上并没有过多地考虑这种事情,而是从他们的编译器中采用更"脚踏实地","常识"的方法.但我更倾向于严格按照标准编码,以尽可能避免意外.

c++ c++11

12
推荐指数
1
解决办法
268
查看次数

在向列表添加项目时如何遍历列表

我有一个线段列表(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将新元素用作最近清空的向量。

有更好的方法吗?

c++ vector

5
推荐指数
1
解决办法
1668
查看次数

如果跨线程共享变量,将变量标记为volatile是否有用?

注意!

我显然没有向这里的每个人清楚地表明我的观点,这令人非常沮丧.我的目标是打消那种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的类而是一个类类型怎么样?

c++ multithreading volatile c++11

4
推荐指数
1
解决办法
962
查看次数

当 X 不成立时,“实现可能假设 X”意味着未定义的行为?

最近有人试图说服我cppreference是错误的,因为它说没有副作用的无限循环将是未定义的行为。与无限循环是否未定义相关的一个问题是无限循环与无限递归。两者都是未定义的吗?。接受的答案引用了标准并得出结论:是的,没有副作用的无限循环是未定义的行为。

其他相关问题有:

相关引用是([basic.progress]p1):

该实现可能假设任何线程最终都会执行以下操作之一:

  • 终止,
  • 调用库 I/O 函数,
  • 通过易失性左值执行访问,或者
  • 执行同步操作或原子操作。

当标准说“实现可能假设 X”时,这种措辞是否意味着包含“非 X”的代码未定义?

(在这个例子中,这意味着egfor (;;);是未定义的,但我很好奇该措辞的一般含义)

c++ undefined-behavior language-lawyer

3
推荐指数
1
解决办法
223
查看次数

是否有明确定义的随机循环终止条件?

考虑以下这个机构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毫秒.

将循环终止条件作为变化的(伪)随机数的基础是明确定义的行为吗?如果不是,那是什么行为?

c++ random undefined-behavior language-lawyer

1
推荐指数
1
解决办法
230
查看次数

clang无限尾递归优化

#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)

c++ tail-recursion clang++

1
推荐指数
1
解决办法
963
查看次数

我的while语句是无限循环?

#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)

c++ while-loop

-4
推荐指数
1
解决办法
798
查看次数