gpt4 book ai didi

c++ - Clang 14 和 15 显然优化了在 Clang 13、ICC、GCC、MSVC 下按预期编译的代码

转载 作者:行者123 更新时间:2023-12-05 08:15:43 24 4
gpt4 key购买 nike

我有以下示例代码:

inline float successor(float f, bool const check)
{
const unsigned long int mask = 0x7f800000U;
unsigned long int i = *(unsigned long int*)&f;

if (check)
{
if ((i & mask) == mask)
return f;
}

i++;

return *(float*)&i;
}

float next1(float a)
{
return successor(a, true);
}

float next2(float a)
{
return successor(a, false);
}

x86-64 clang 13.0.1 下,代码按预期编译。

x86-64 clang 14.0.0 或 15 下,输出只是 next1(float)ret 操作>next2( float )

编译器选项:-march=x86-64-v3 -O3

代码和输出在这里:Godbolt .

successor(float,bool) 函数不是空操作。

请注意,输出符合 GCC、ICC 和 MSVCC 的预期。我在这里遗漏了什么吗?

最佳答案

*(unsigned long int*)&f 是直接的别名违规。 f 是一个 float 。您不能通过指向 unsigned long int 的指针访问它。 (这同样适用于 *(float*)&i。)

因此代码具有未定义的行为,Clang 喜欢假设具有未定义行为的代码是不可访问的。

使用 -fno-strict-aliasing 编译以强制 Clang 不将别名违规视为不会发生的未定义行为(尽管此处可能还不够,见下文)或最好不要依赖未定义的行为。而是使用 std::bit_cast(C++20 起)或 std::memcpy 来创建具有新类型的 f 的拷贝但相同的对象表示。这样你的程序将是有效的标准 C++,而不依赖于 -fno-strict-aliasing 编译器扩展。

(如果您使用 std::memcpy 添加一个 static_assert 来验证 unsigned long intfloat 具有相同的大小。并非所有平台都如此,也并非所有常见平台都如此。std::bit_cast 具有内置测试。)


正如@CarstenS 在另一个答案中所注意到的,鉴于您(至少在编译器资源管理器上)正在为 SysV ABI 进行编译,unsigned long int(64 位)确实与 float (32 位)。因此,在 i 的初始化中,您正在越界访问内存,因此存在更直接的 UB。正如他还注意到的那样,即使没有 -fno-strict-aliasing,当使用整数类型的匹配大小时,Clang 似乎确实会按预期编译代码。不过,这并不会使我上面写的内容失效。

关于c++ - Clang 14 和 15 显然优化了在 Clang 13、ICC、GCC、MSVC 下按预期编译的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73843430/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com