为什么我会收到“假设不发生有符号整数溢出”?

问题描述 投票:0回答:1

有问题的代码(godbolt

#include <stdbool.h>
void do_work(void);

typedef struct task {
    int timer;
    void (*job)(void);
} task_t;

typedef struct task_list {
    task_t *tasks;
    int length;
} task_list_t;

void test(task_list_t *task_list)
{
    for (int i = 0; i < task_list->length; i++)
    {
        task_t *task = &task_list->tasks[i];
        __attribute__((assume(task->timer > 0)));
        task->timer--;
        bool timer_finished = task->timer <= 0;
        if (timer_finished)
            task->job();
    }
}

我得到以下输出:

<source>: In function 'test':
<source>:25:1: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C2 -+ C1 [-Wstrict-overflow]
   25 | }
      | ^
<source>:25:1: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C2 -+ C1 [-Wstrict-overflow]
Compiler returned: 0

假设我无法将 tast_t::timer 更改为无符号,为什么假设被忽略?或者我从根本上误解了这个警告?

c gcc
1个回答
0
投票

您收到的警告

warning: assuming signed overflow does not occur [...] [-Wstrict-overflow]
是由于编译器让您知道它假设您的整数变量task_t::timer在递减时永远不会是INT_MIN(
task->timer--;
)。 当变量已达到最小值时递减变量会导致上溢(或下溢),C 标准将其定义为未定义行为 (UB)。

编译器假设它不会溢出,以优化生成的机器代码。它发出警告是因为,在优化以下内容时:

bool timer_finished = task->timer <= 0;

它假设

task->timer
不会溢出。如果是这样,由于 UB 的原因,比较可能会出现意想不到的结果。

__attribute__((assume))
帮助编译器了解特定点的某些属性,但它不会影响有关代码中整数溢出的假设。编译器仍然遵循 C 标准,这允许它在有符号溢出为 UB 的假设下进行优化。

要抑制警告,您需要向编译器明确表示,当可能出现有符号溢出时,永远不会执行比较,例如:

if (task->timer > 0) {
    task->timer--;
    bool timer_finished = task->timer <= 0;
    if (timer_finished)
        task->job();
}

这确保了`task->timer仅在为正数时递减,避免潜在的下溢问题并使编译器更快乐并且不会发出警告:)

© www.soinside.com 2019 - 2024. All rights reserved.