C++ code below demonstrates how GCC 13 optimizes std::memcpy and a temporary std::array:
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <new>
#include <type_traits>
template <class T>
T* startLifetimeAs(void* const buffer)
{
std::array<std::byte, sizeof(T)> representation;
// Preserve the bytes before placement new ends the previous lifetime.
std::memcpy(representation.data(), buffer, representation.size());
// Start the lifetime of T in the original storage.
T* const result = ::new (buffer) T;
// Initialize the object representation of the newly created T.
std::memcpy(result, representation.data(), representation.size());
return result;
}
int main()
{
constexpr std::uint32_t expected = 0x12345678;
alignas(std::uint32_t)
std::byte buffer[sizeof(std::uint32_t)];
// Simulate bytes received from an external source.
std::memcpy(buffer, &expected, sizeof(expected));
std::uint32_t* const value =
startLifetimeAs<std::uint32_t>(buffer);
std::cout
<< "Value: 0x"
<< std::hex
<< std::setfill('0')
<< std::setw(8)
<< *value
<< '\n';
return *value == expected ? 0 : 1;
}
Compile options:
g++ -std=c++23 \
-O2 \
-march=native \
-Wall -Wextra \
example.cpp -o example
GCC 13.3 generates the following code:
.globl std::ios_base_library_init()
.LC0:
.string "Value: 0x"
main:
push r12
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:std::cout
push rbp
push rbx
sub rsp, 16
call std::basic_ostream<char, std::char_traits<char>>& std::operator<<<std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&, char const*)
mov rdx, QWORD PTR [rax]
mov rbp, rax
mov rbx, QWORD PTR [rdx-24]
add rbx, rax
mov eax, DWORD PTR [rbx+24]
and eax, -75
or eax, 8
cmp BYTE PTR [rbx+225], 0
mov DWORD PTR [rbx+24], eax
mov rax, rbx
je .L18
.L4:
mov BYTE PTR [rbx+224], 48
mov rdi, rbp
mov esi, 305419896
mov QWORD PTR [rax+16], 8
call std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long)
mov BYTE PTR [rsp+15], 10
mov rdi, rax
mov rax, QWORD PTR [rax]
mov rax, QWORD PTR [rax-24]
cmp QWORD PTR [rdi+16+rax], 0
jne .L19
mov esi, 10
call std::ostream::put(char)
.L10:
add rsp, 16
xor eax, eax
pop rbx
pop rbp
pop r12
ret
.L19:
mov edx, 1
lea rsi, [rsp+15]
call std::basic_ostream<char, std::char_traits<char>>& std::__ostream_insert<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&, char const*, long)
jmp .L10
.L18:
mov r12, QWORD PTR [rbx+240]
test r12, r12
je .L20
cmp BYTE PTR [r12+56], 0
je .L21
.L7:
mov rax, QWORD PTR [rdx-24]
mov BYTE PTR [rbx+225], 1
add rax, rbp
jmp .L4
.L21:
mov rdi, r12
call std::ctype<char>::_M_widen_init() const
mov rax, QWORD PTR [r12]
mov rax, QWORD PTR [rax+48]
cmp rax, OFFSET FLAT:_ZNKSt5ctypeIcE8do_widenEc
jne .L14
.L17:
mov rdx, QWORD PTR [rbp+0]
jmp .L7
.L14:
mov esi, 32
mov rdi, r12
call rax
jmp .L17
.L20:
call std::__throw_bad_cast()

