c++ - 现代 C++ 编译器会在类型转换后优化赋值吗?

标签 c++ optimization strict-aliasing

采用以下代码:

char chars[4] = {0x5B, 0x5B, 0x5B, 0x5B};
int* b = (int*) &chars[0];

(int*) &chars[0] 值将在循环(长循环)中使用。在我的代码中使用 (int*) &chars[0] 而不是 b 有什么优势吗?创建 b 是否有任何开销?因为我只想将它用作别名并提高代码可读性。

此外,只要我知道自己在做什么,就可以进行这种类型转换吗?或者我应该总是 memcpy() 到另一个具有正确类型的数组并使用它吗?我会遇到任何一种未定义的行为吗?因为到目前为止,在我的测试中,它是有效的,但我看到人们不鼓励这种类型转换。

最佳答案

is it OK to do this kind of type casting as long as I know what I'm doing?

不,这不行。 这不安全。 C++ 标准不允许这样做。您可以访问对象表示(即,将对象指针转换为 char*),尽管结果取决于目标平台(由于 endianess 和填充)。但是,您不能安全地做相反的事情(即没有未定义的行为)。

更具体地说,int 类型可以有不同的对齐要求(通常对齐到 4 或 8 个字节)而不是 char(不对齐) .因此,您的数组可能未对齐,并且当 b 将被取消引用时,强制转换会导致未定义的行为。请注意,它可能会导致某些处理器(例如 AFAIK、POWER)崩溃,尽管主流 x86-64 处理器支持它。此外,编译器可以假定 b 在内存中对齐 (ot alignof(int))。

Or should I always memcpy() to another array with the correct type and use that?

是的,或者像新的 std::bit_cast 这样的替代 C++ 操作自 C++20 起可用。不必担心性能:大多数编译器(GCC、Clang、ICC,当然还有 MSVC)会优化此类操作(称为类型双关)。

Would I encounter any kind of undefined behavior?

如前所述,是的,只要类型双关没有正确完成。有关这方面的更多信息,您可以阅读以下链接:

because in my testing so far, it works, but I've seen people discouraging this kind of type casting.

它通常适用于 x86-64 处理器上的简单示例。但是,当您处理大代码时,编译器会执行愚蠢的优化(但对于 C++ 标准而言是完全正确的)。引用cppreference :“编译器不需要诊断未定义的行为(尽管很多简单的情况都被诊断出来),并且编译后的程序不需要做任何有意义的事情。”。此类问题很难调试,因为它们通常仅在启用优化时以及在某些特定情况下才会出现。程序的结果可能会因函数内联而改变,这取决于编译器试探法。在您的情况下,这取决于堆栈的对齐方式,堆栈对齐方式取决于编译器优化和当前范围内声明/使用的变量。一些处理器不支持未对齐的访问(例如,跨越缓存行边界的访问),这会导致数据损坏的硬件异常。

所以简而言之,到目前为止“有效”并不意味着它会随时随地有效。

The (int*) &chars[0] value is going to be used in a loop (a long loop). Is there any advantage in using (int*) &chars[0] over b in my code? Is there any overhead in creating b? Since I only want to use it as an alias and improve code readability.

假设您使用正确的方式进行类型双关(例如memcpy),那么只要启用优化标志,优化编译器就可以完全优化此初始化。除非您发现生成的代码优化不佳,否则您不应该担心这一点。 正确性比性能更重要

关于c++ - 现代 C++ 编译器会在类型转换后优化赋值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70843952/

相关文章:

c++ - 如何调用在另一个 stackoverflow 中找到的已创建仿函数对象?

删除空白的 asp.net 发布

c# - 这段代码可以优化吗?

excel - 为什么这个 VBA 代码运行时间太长?

c - gcc、严格别名和恐怖故事

c - C 中的灵活数组和取消引用类型双关指针错误

c++ - 在哪里声明类成员模板的偏特化?

C++构造函数和并发

c++ - char* 和 std::uint8_t* 之间的 reinterpret_cast - 安全吗?

c++ - CodeLite 中的graphics.h?