相关疑难解决方法(0)

GCC 删除了 && 右操作数中的边界检查,但没有删除左操作数中的边界检查,为什么?

我有以下 C/C++ 代码片段:

#define ARRAY_LENGTH 666

int g_sum = 0;
extern int *g_ptrArray[ ARRAY_LENGTH ];

void test()
{
    unsigned int idx = 0;

    // either enable or disable the check "idx < ARRAY_LENGTH" in the while loop
    while( g_ptrArray[ idx ] != nullptr /* && idx < ARRAY_LENGTH */ )
    {
        g_sum += *g_ptrArray[ idx ];
        ++idx;
    }

    return;
}
Run Code Online (Sandbox Code Playgroud)

当我使用版本 12.2.0 中的 GCC 编译器编译上述代码时,并选择-Os两种情况:

  1. while 循环条件是g_ptrArray[ idx ] != nullptr
  2. while 循环条件是g_ptrArray[ idx ] != …

c c++ arrays gcc compiler-optimization

32
推荐指数
3
解决办法
4196
查看次数

如果 C 编译器无法证明缺少 UB,为什么要禁止优化?

如果 C 程序有未定义的行为,任何事情都可能发生。因此编译器可能会假设任何给定的程序不包含 UB。因此,假设我们的程序包含以下内容:

\n
x += 5;\n/* Do something else without x in the meantime. */ \nx += 7;\n
Run Code Online (Sandbox Code Playgroud)\n

当然,这可以优化为

\n
/* Do something without x. */\nx += 12;\n
Run Code Online (Sandbox Code Playgroud)\n

或类似的其他方式。

\n

如果 x 具有类型,unsigned int则上述程序中不可能出现 UB。另一方面,如果 x 有类型signed int,则有可能溢出,从而产生 UB。由于编译器可能会假设我们的程序不包含UB,因此我们可以进行与上面相同的优化。事实上,在这种情况下,编译器甚至可以假设x - 12 <= MAX_INT.

\n

然而,这似乎与 Jens Gustedt 著名的“Modern C”(第 42 页)相矛盾:

\n
\n

但这样的优化也可以被禁止,因为编译器无法证明某个操作不会强制程序终止。在我们的示例中,很大程度上取决于 x 的类型。如果 x 的当前值可能接近类型的上限,则看似无辜的操作 x += 7 可能会产生溢出。此类溢出根据类型的不同而有不同的处理方式。正如我们所看到的,无符号类型的溢出不是问题,并且压缩运算的结果将始终与两个单独的结果一致。对于其他类型,例如有符号整数类型(signed)和浮点类型(double),溢出可能会引发异常并终止程序。在这种情况下,无法执行优化。

\n
\n

(强调我的)。如果编译器可以(并且确实)假设我们的程序没有 UB,为什么不能执行此优化?

\n …

c optimization integer-overflow compiler-optimization undefined-behavior

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

具有从未实际执行的未定义行为的表达式是否会导致程序错误?

在关于未定义行为(UB)的许多讨论中,已经提出了这样的观点:在程序中存在任何具有UB的任何构造的程序都要求一致的实现做任何事情(包括什么都没有).我的问题是,即使在UB与代码执行相关联的情况下,是否应该采取这种方式,而标准中规定的行为(否则)规定不应执行相关代码(这可能是对于程序的特定输入;它可能在编译时不可判定).

更加非正式地说,UB的气味是否要求一致的实现来决定整个程序发臭,并且拒绝正确执行甚至行为完全明确定义的程序部分.一个示例程序将是

#include <iostream>

int main()
{
    int n = 0;
    if (false)
      n=n++;   // Undefined behaviour if it gets executed, which it doesn't
    std::cout << "Hi there.\n";
}
Run Code Online (Sandbox Code Playgroud)

为清楚起见,我假设程序格式正确(因此特别是UB与预处理无关).事实上,我愿意将UB限制为与"评估"相关联,而"评估"显然不是编译时实体.我认为,与给出的例子相关的定义(重点是我的):

之前排序的是由单个线程(1.10)执行评估之间的不对称,传递,成对关系,这导致这些评估之间的部分顺序

在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于...或使用相同标量对象的值进行值计算未被排序,则行为未定义.

隐含地清楚的是,最后一句中的主语"副作用"和"价值计算"是"评价"的实例,因为这就是定义"之前排序"的关系.

我认为在上述程序中,标准规定不进行评价,以满足最后一句中的条件(相对于彼此和所描述的类型),并且该程序不具有UB; 这不是错误的.

换句话说,我确信我的标题问题的答案是否定的.但是,我会很感激其他人对此事的(动机)意见.

对于那些主张肯定答案的人来说,可能还有一个问题是,当编译错误的程序时,会强制重新格式化硬盘吗?

本网站上的一些相关指针:

c++ undefined-behavior language-lawyer

19
推荐指数
3
解决办法
1117
查看次数

C++最早的未定义行为可以表现出来的是什么?

我知道未定义的行为可能会导致任何事情,这使得任何包含UB的程序都可能毫无意义.我想知道是否有任何方法可以确定程序中最早的一点,即未定义的行为可能会导致问题.这是一个例子来说明我的问题.

void causeUndefinedBehavior()
{
   //any code that causes undefined behavior
   //every time it is run
   char* a = nullptr;
   *a;
}


int main()
{
 //code before call
 //...
 causeUndefinedBehavior();
 //code after call
 //...
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,可能引发未定义行为的可能时间(不一定表现出来)是:

  1. 何时causeUndefinedBehavior()编译.
  2. 何时main()编译.
  3. 在程序运行时.
  4. 当时causeUndefinedBehavior()执行.

或者,对于每个案例和每个实现,未定义的行为都会被完全不同?

另外,如果我注释掉causeUndefinedBehavior()调用的行,是否会消除UB,或者它是否仍然在程序中,因为编译了包含UB的代码?

c++ undefined-behavior

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

导致时间旅行的未定义行为

来自msdn博客的这篇文章的一个例子让我做了自动收报机:

它说这个功能:

void unwitting(bool door_is_open)
{
    if (door_is_open) {
        walk_on_in();
    } else {
        ring_bell();

        // wait for the door to open using the fallback value
        fallback = value_or_fallback(nullptr);
        wait_for_door_to_open(fallback);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以优化到这一个:

void unwitting(bool door_is_open)
{
    walk_on_in();
}
Run Code Online (Sandbox Code Playgroud)

因为调用value_or_fallback(nullptr)是未定义的行为(这在本文前面已经证明).

现在我不明白的是:运行时只有在到达该行时才进入未定义的行为.在运行时进入UB之前,第一段的所有可观察效果是否都应该被解决,这不应该发生在之前/之后发生的概念吗?

c++ undefined-behavior

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

如果程序的一部分表现出未定义的行为,它会影响程序的其余部分吗?

假设程序员忘记初始化他的一个自动变量,并且他使用了它的值,从而调用了未定义的行为.

...
int i = 0, j;
...
printf("value of 'j': %d\n", j);
...
...
char buf[256];
fputs("Enter query:", stdout);
fgets(buf, sizeof(buf), stdin);
... //process input
... perform other tasks
Run Code Online (Sandbox Code Playgroud)

程序员注意到屏幕上出现了乱码,并意识到他的程序是错误的,但它并没有崩溃,反正还在继续.

假设在此之后,程序提示用户输入并期望处理它,显示结果并执行所有独立于未初始化变量的其他任务,鼓励程序员停止使用该程序,修复错误,重新编译和运行?该计划的其余部分是否会不一致?

c c++ undefined-behavior

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

当函数有警告 [-Wreturn-type] 时,为什么优化会忽略 if 语句?

操作系统:ubuntu2204

编译器:gcc 11.2 x86_64

这是一个简单的代码:


#include <cstdlib>

int func(int val) {
    if (val == 1) {
    } else {
        abort();
    }
}

int main(int argc, char* argv[]) {
    func(argc);
}

Run Code Online (Sandbox Code Playgroud)

当我在没有任何优化的情况下编译它并运行它时,它工作正常。

但是当我用 编译它时g++ tmp.cpp -O3,结果func会忽略输入值,而只调用abort.

当然,我可以通过在 的末尾添加 return 语句来修复它func,但是,为什么呢?

这是objdump -d a.out优化函数的一些输出func


0000000000001060 <_Z4funci>:
    1060:   f3 0f 1e fa             endbr64 
    1064:   50                      push   %rax
    1065:   58                      pop    %rax
    1066:   50                      push   %rax
    1067:   e8 e4 ff ff ff …
Run Code Online (Sandbox Code Playgroud)

c++ optimization assembly compiler-optimization undefined-behavior

4
推荐指数
2
解决办法
228
查看次数