Zynq Ultrascale+平台编译器优化导致循环提前退出问题咨询
编译器优化导致循环提前退出的原因分析
在Zynq Ultrascale+ ARM核心上使用aarch64-none-elf-g++开发时,遇到了编译器优化相关的异常:开启-O2优化后,代码中的循环会提前退出,而-O0优化级别下行为符合预期。
复现代码
#include <cstdint> #include <string> #include <vector> class TestClass { private: std::vector<int> command_buffer; public: TestClass() : command_buffer({}) {} void read_command(); }; void TestClass::read_command() { printf("Before %lu\n", 67ul); size_t s = 42; while (true) { s = this->command_buffer.size(); if (s > 0) { break; } } printf("Size %lu:\n", s); } int main() { TestClass tester{ }; tester.read_command(); }
预期与实际输出
- 无优化(-O0)输出:
Before: 67
(程序无限循环,无后续输出)
- -O2优化输出:
Before: 67
Size: 0
问题汇编代码
.LC0: .string "Before: %lu\n" .align 3 .LC1: .string "Size: %lu\n" .text .align 2 .p2align 4,,11 .global _ZN9TestClass12read_commandEv .type _ZN9TestClass12read_commandEv, %function _ZN9TestClass12read_commandEv: .LFB2157: .cfi_startproc stp x29, x30, [sp, -32]! .cfi_def_cfa_offset 32 .cfi_offset 29, -32 .cfi_offset 30, -24 adrp x1, .LC0 mov x29, sp str x19, [sp, 16] .cfi_offset 19, -16 mov x19, x0 add x0, x1, :lo12:.LC0 mov x1, 67 bl printf ldp x2, x1, [x19] adrp x0, .LC1 ldr x19, [sp, 16] add x0, x0, :lo12:.LC1 ldp x29, x30, [sp], 32 .cfi_restore 30 .cfi_restore 29 .cfi_restore 19 .cfi_def_cfa_offset 0 sub x1, x1, x2 asr x1, x1, 2 b printf .cfi_endproc
问题原因
这个问题的核心是编译器基于C++标准的"as-if"规则和未定义行为的优化:
- 代码中的
command_buffer是当前线程的私有变量,在read_command的循环体内,没有任何代码会修改该vector的大小,也没有同步机制(如volatile、原子操作、互斥锁)允许其他线程修改它。编译器在-O2优化时会判定:command_buffer.size()的返回值是恒定不变的,初始值为0。 - 循环逻辑是"当size为0时持续循环",这属于无限循环且无任何可观测行为(既没有IO操作,也没有修改
volatile变量或其他会影响外部环境的操作)。根据C++标准,这种无限循环属于未定义行为。 - 对于未定义行为,编译器可以任意处理,这里它直接优化掉了整个循环逻辑,直接执行后续的
printf语句,导致程序提前退出。 - 而-O0级别下,编译器关闭了大部分优化,会严格按照代码的字面逻辑执行,每次循环都会重新读取vector的size,因此表现为无限循环,符合预期。
内容的提问来源于stack exchange,提问作者Matthew Dvorsky
相关产品推荐
相关产品推荐

