그의 최근 강연에서 “현대 C의 유형 말장난 ++” 티무르 Doumler는 말했다 그 std::bit_cast
비트가 캐스팅에 사용할 수 없습니다 float
에 unsigned char[4]
C 스타일 배열은 함수에서 반환 할 수 없기 때문에. 우리는 std::memcpy
비슷한 것을 reinterpret_cast<unsigned char*>(&f)[i]
잘 정의 할 때 C ++ 23 (또는 그 이후 버전)을 사용 하거나 기다려야 합니다.
C ++ 20에서 우리가 사용할 수 std::array
와 함께 std::bit_cast
,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
C 스타일의 배열 대신에 float
?
답변
예, 이것은 모든 주요 컴파일러에서 작동하며 표준을 살펴보면 이식성이 뛰어나고 작동합니다.
우선 std::array<unsigned char, sizeof(float)>
집계 ( https://eel.is/c++draft/array#overview-2 ) 가 보장됩니다 . 이것으로부터 내부에 정확히 sizeof(float)
많은 숫자가 char
들어 char[]
갑니다 (일반적으로 a 는 afaics 표준은이 특정 구현을 요구하지 않지만 요소는 연속적이어야한다고 말하지만) 추가 비 정적 멤버를 가질 수 없습니다.
따라서 사소한 복사가 가능하며 크기도 float
동일합니다.
이 두 속성을 사용하면 둘 bit_cast
사이에있을 수 있습니다.
답변
정렬 및 패딩 문제를 고려하지 않았으므로 허용 된 답변이 잘못되었습니다.
[배열] / 1-3 당 :
헤더
<array>
는 고정 크기의 객체 시퀀스를 저장하기위한 클래스 템플릿을 정의합니다. 배열은 연속 컨테이너입니다. 인스턴스의array<T, N>
저장N
형태의 소자는T
, 그래서 그것은size() == N
불변이다.배열은
N
유형을로 변환 할 수있는 최대 요소 까지 목록으로 초기화 할 수있는 집계입니다T
.배열
[container.requirements]
은 기본 생성 된 배열 객체가 비어 있지 않고 스왑에 일정한 복잡성이 없다는 점을 제외하고 컨테이너 및 가역 컨테이너 ( ) 의 모든 요구 사항을 충족합니다 . 배열은 시퀀스 컨테이너의 일부 요구 사항을 충족합니다. 여기에서는 이러한 테이블 중 하나에 설명되지 않은 배열에 대한 조작과 추가 의미 정보가있는 조작에 대해서만 설명합니다.
표준은 실제로 std::array
정확히 하나의 공개 데이터 멤버를 가질 필요가 없으므로 T[N]
이론 상으로는 sizeof(To) != sizeof(From)
또는 가능합니다 is_trivially_copyable_v<To>
.
그래도 이것이 실제로 작동하지 않으면 놀랄 것입니다.
답변
예.
에 따라 종이 의 동작을 설명 std::bit_cast
하고, 그 제안 구현 까지 두 가지 유형이 같은 크기를 가지고만큼 하찮게 캐스트가 성공해야 복사 가능한.
단순화 된 구현은 std::bit_cast
다음과 같아야합니다.
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
static_assert(sizeof(Dest) == sizeof(Source));
static_assert(std::is_trivially_copyable<Dest>::value);
static_assert(std::is_trivially_copyable<Source>::value);
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
모든 주장 unsigned char
과 size_of(float)
관련 하여 float (4 바이트) 및 배열이므로 기본 std::memcpy
이 수행됩니다. 따라서 결과 배열의 각 요소는 float의 연속 된 1 바이트입니다.
이 동작을 증명하기 위해 컴파일러 탐색기에서 https://godbolt.org/z/4G21zS에서 시도 할 수있는 작은 예제를 작성했습니다 . float 5.0은 Big EndianOx40a00000
에서 해당 float 숫자의 16 진수 표현에 해당하는 바이트 배열 ( ) 로 올바르게 저장됩니다 .