通过强制转换在 uint8_t[8] 和 uint64_t 之间安全转换?

标签 c optimization casting memcpy memory-alignment

我目前的做法(我更愿意摆脱 memcpy 调用):

uint64_t integer;
uint8_t string[8];
...
memcpy(&integer, &string, 8); //or swap the parameters

假设整数数组长度始终是 8 的倍数(64 位总分配)考虑到编译器填充/对齐问题,可以进行直接转换吗?

最佳答案

如果您正在努力优化,那么绝对没有必要避免或替换 memcpy() 调用。每个现代优化编译器都不会发出调用并生成等效的汇编代码。较新的 GCC 和 Clang 版本甚至在没有给出优化相关选项的情况下也会这样做。顺便说一句,可以使用 -fno-builtin 禁用该行为。

您可以使用 C++ Compiler Explorer 自行验证这一点(当然,或者在本地使用 -S):

#include <string.h>
#include <stdint.h>

uint64_t
u8tou64(uint8_t const u8[static 8]){
  uint64_t u64;
  memcpy(&u64, u8, sizeof u64);
  return u64;
}

例如,针对 x86_64 的 GCC 4.8.1 会产生:

u8tou64:
    push    rbp
    mov rbp, rsp
    mov QWORD PTR [rbp-24], rdi
    mov rax, QWORD PTR [rbp-24]
    mov rax, QWORD PTR [rax]
    mov QWORD PTR [rbp-8], rax
    mov rax, QWORD PTR [rbp-8]
    pop rbp
    ret

使用-O3:

u8tou64:
    mov rax, QWORD PTR [rdi]
    ret

This blog post John Regehr 得出了相同的结论(c5() 调用 memcpy()):

In my opinion c5 is the easiest code to understand out of this little batch of functions because it doesn’t do the messy shifting and also it is totally, completely, obviously free of complications that might arise from the confusing rules for unions and strict aliasing. It became my preferred idiom for type punning a few years ago when I discovered that compilers could see through the memcpy and generate the right code.

使用 union 或按位运算等替代方案可能不会产生最佳(且看起来不错)代码,或者不能在 ISO C90 或 C++ 中使用(这还包括提到的 GCC 的 __may_alias__ 属性在评论部分)。

关于通过强制转换在 uint8_t[8] 和 uint64_t 之间安全转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29195075/

相关文章:

c - C中的冒泡排序文件

c - 线程创建。我正在用最后一个线程覆盖所有线程

c - 将 autotools 与 README.md 一起使用

c - GCC是否缓存循环变量?

c - 点积 - SSE2 与 BLAS

C++ 以编程方式转换 : can it be done?

使用 printf 和 scanf 的 C 程序在输入时崩溃

c++ - 用于检查数字是否在特定范围内的位旋转

c++ - 编译器在哪里存储 C++ 类的方法?

time - 将 <integer> 秒添加到 PostgreSQL 中的 <timestamp>