我在我们的 C++ iOS 应用程序中发现了一个严重的错误,我怀疑这是由基于 ARM 的 Apple Clang 上的编译器错误引起的。
我能够在 Mac M1 机器上的 MRE 中重现该错误。
#include <cstdio>
int main(int argc, const char** argv)
{
int total = 0;
for(double a=1000; a<10000; a*=1.1)
{
unsigned char d = a / 0.1;
total += d;
}
printf("Total: %d\n", total);
}
Run Code Online (Sandbox Code Playgroud)
在没有优化的情况下编译,测试程序总是产生相同的输出:
% ./a.out
Total: 3237
% ./a.out
Total: 3237
% ./a.out
Total: 3237
Run Code Online (Sandbox Code Playgroud)
然而,当进行优化编译时,结果数字似乎是随机的:
% clang -O3 test.cpp
% ./a.out
Total: 74841976
% ./a.out
Total: 71057272
% ./a.out
Total: 69828472
Run Code Online (Sandbox Code Playgroud)
Apple Clang 版本为 13.0:
% clang --version
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: arm64-apple-darwin21.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Run Code Online (Sandbox Code Playgroud)
我相信该程序没有未定义的行为。所以我的问题是:
您的代码确实有未定义的行为。当你这样做时
unsigned char d = a / 0.1;
Run Code Online (Sandbox Code Playgroud)
您正在进行浮点到整数的转换,这意味着[conv.fpint]/1适用并且它指出:
浮点类型的纯右值可以转换为整数类型的纯右值。转换截断;也就是说,小数部分被丢弃。如果截断值无法在目标类型中表示,则行为未定义。
强调我的
因此,一旦a / 0.1超过 an 的最大值,unsigned char您就会出现未定义的行为。