You need to enable JavaScript to run this app. 求解AoC2020第13题的C代码经gcc -O2优化后死循环,求修复未定义行为
优惠活动
大模型
产品
解决方案
定价
更多

求解AoC2020第13题的C代码经gcc -O2优化后死循环,求修复未定义行为

代码运行的优化等级差异问题

我编写了一段用于求解2020年Advent of Code第13题的C代码,清楚知道暴力法大概率不是最优解法,但这段程序在示例输入下可以输出正确结果,实际运行表现和编译优化等级强相关:

  • 使用gcc搭配-O1参数编译时,程序可正常输出正确结果
  • 更换为-O2参数编译时,程序会直接陷入死循环
  • 即使编译时添加了-Wall -Wextra -pedantic参数,编译器也没有给出任何相关警告

我最初猜测存在未定义行为,问题可能和found变量始终无法被置为非0值、进而导致time变量溢出有关。为了规避溢出风险,我尝试将while循环的头部条件修改为(!found && time < 10000000000),结果在-O2编译下程序会直接跳出循环,退出时time值为10000000003,而-O1编译下程序依然能得到正确结果。
这段代码的正确输出应为1068781,问题代码如下:

#include <stdio.h>
int main()
{
    unsigned int busses[] = {7, 0, 13, 2, 59, 1, 31, 0, 19};
    unsigned int busses_used = 9;
    unsigned int i = 0;
    unsigned int found = 0;
    unsigned long long time = 0;
    unsigned int offset = 0;
    unsigned int increment = 7;
    while (!found) {
        time += increment;
        offset = 0;
        for (i = 0; i < busses_used; i++) {
            if ((time + offset) % busses[i] == 0) {
                found = 1;
                offset++;
            } else {
                found = 0;
                break;
            }
            offset += busses[++i];
        }
    }
    printf("Endtime: %lld\n", time);
    return 0;
}

问题根因与修复

经过排查,代码的核心未定义行为是数组越界访问:
for循环内执行offset += busses[++i];时,当i遍历到原数组最后一个合法下标(对应值19,下标为8),自增后的i值变为9,此时访问busses[9]已经超出数组实际长度9的边界。
这类运行时越界的未定义行为,不同优化等级下会触发完全不可预期的执行流:-O1下编译器未做激进优化,碰巧让程序跑出了正确结果;-O2下编译器基于“合法C代码不会访问越界内存”的前提做优化,就会出现死循环、提前退出等异常表现,且常规编译警告参数无法提前捕获这类问题。感谢KamilCuk指出这段代码存在数组越界访问的问题,并指导定位这类问题的方法。

修复方案

在busses数组末尾追加一个0元素,同时将busses_used的值从9修改为10,让所有数组下标访问都落在合法边界内,即可消除未定义行为,不同优化等级下的运行结果将保持一致。

内容的提问来源于stack exchange,提问作者Stephan Hegemann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.13 13:36:04