使用 memcpy 初始化位填充结构
Using memcpy to initialize bit padded struct
有谁知道为什么位填充结构的初始化是 "bad thing" 而不能使用?
例如:
struct parameter_set_t
{
std::uint8_t m_profile_idc;
bool m_constraint_set0_flag: 1;
bool m_constraint_set1_flag : 1;
bool m_constraint_set2_flag : 1;
bool m_constraint_set3_flag : 1;
bool m_constraint_set4_flag : 1;
bool m_constraint_set5_flag : 1;
std::uint8_t m_reserved_zero_2bits : 2;
std::uint8_t m_level_idc;
};
inline std::uint32_t bswap32(std::uint32_t v )
{
std::uint32_t ret_value = 0;
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
ret_value = __builtin_bswap32(v);
#else
ret_value = ((v & 0x000000FF) << 24) | ((v & 0x0000FF00) << 8) | ((v & 0x00FF0000) >> 8) | ((v & 0xFF000000) >> 24);
#endif
return ret_value;
}
//! build from sdp 0xAABBCC string
profile_level_id( const std::string& sdp_value )
{
//fetch profile_level_id value
std::uint32_t int_value = std::stoul( sdp_value, nullptr, 16 );
int_value = bswap32( int_value ) >> 8;
std::memcpy( &m_parameters, &int_value, sizeof( parameter_set_t ) );
}
问题不在于使用了 std::memcpy
,而是用于在不兼容的源类型和目标类型之间进行复制。
数据是从一个32位的无符号整数中读取的,但它被写入一个parameter_set_t
结构,其大小为24位。因此,uint32_t
的 8 位被丢弃。这给我们留下了两个问题:
- 丢弃了哪 8 位,最低位还是最高位?
- 整数的 24 位在
struct
的 24 位之间如何分布?
这两个问题的答案都是 "it is platform-specific",这是 "completely non-portable" 的一种很好的表达方式。因此,评论中对该代码段的质量进行了咒骂。
请注意,如果复制是在 parameter_set_t
的两个实例之间完成的,那么使用 std::memcpy
就完全没问题了。
有谁知道为什么位填充结构的初始化是 "bad thing" 而不能使用?
例如:
struct parameter_set_t
{
std::uint8_t m_profile_idc;
bool m_constraint_set0_flag: 1;
bool m_constraint_set1_flag : 1;
bool m_constraint_set2_flag : 1;
bool m_constraint_set3_flag : 1;
bool m_constraint_set4_flag : 1;
bool m_constraint_set5_flag : 1;
std::uint8_t m_reserved_zero_2bits : 2;
std::uint8_t m_level_idc;
};
inline std::uint32_t bswap32(std::uint32_t v )
{
std::uint32_t ret_value = 0;
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
ret_value = __builtin_bswap32(v);
#else
ret_value = ((v & 0x000000FF) << 24) | ((v & 0x0000FF00) << 8) | ((v & 0x00FF0000) >> 8) | ((v & 0xFF000000) >> 24);
#endif
return ret_value;
}
//! build from sdp 0xAABBCC string
profile_level_id( const std::string& sdp_value )
{
//fetch profile_level_id value
std::uint32_t int_value = std::stoul( sdp_value, nullptr, 16 );
int_value = bswap32( int_value ) >> 8;
std::memcpy( &m_parameters, &int_value, sizeof( parameter_set_t ) );
}
问题不在于使用了 std::memcpy
,而是用于在不兼容的源类型和目标类型之间进行复制。
数据是从一个32位的无符号整数中读取的,但它被写入一个parameter_set_t
结构,其大小为24位。因此,uint32_t
的 8 位被丢弃。这给我们留下了两个问题:
- 丢弃了哪 8 位,最低位还是最高位?
- 整数的 24 位在
struct
的 24 位之间如何分布?
这两个问题的答案都是 "it is platform-specific",这是 "completely non-portable" 的一种很好的表达方式。因此,评论中对该代码段的质量进行了咒骂。
请注意,如果复制是在 parameter_set_t
的两个实例之间完成的,那么使用 std::memcpy
就完全没问题了。