我有一个(char*)缓冲区。我可以做如下操作吗:
int8_t i8 = *(int8_t*)buffer;
int16_t i16 = *(int16_t*)buffer;
float f = *(float*)buffer;
int8_t i = 22; *(int8_t*)buffer = i
int16_t i = 25; *(int16_t*)buffer = i
float f = 16.4; *(float*)buffer = f
EDIT:让我们假设缓冲区是通过以下方式之一创建的:char* buffer = new char[300 * sizeof(char)];
char* buffer = (char*)malloc(300 * sizeof(char));
1条答案
按热度按时间mf98qq941#
对于使用
new
的版本,不能保证它们在所有可能的实现中都有未定义的行为:1.如果
int8_t
不是char
或signed char
(但在我所知道的所有平台上都是这样),则是一个别名冲突(因此是未定义的行为)。如果您没有为buffer[0]
赋值,则它也会阅读一个不确定的值,这也会导致未定义的行为。1.如果
int16_t
不是char
或signed char
,也是一个别名冲突,因为在任何使用CHAR_BIT == 8
的常用平台上都不可能是这样。buffer[0]
的初始化再次丢失。1.肯定是混叠违规。
1.与1相同。减去不确定值问题。
1.同2.减去不定值问题。
1.与3相同。
对于带有
malloc
的版本,假设您只访问过所列类型中 * 只有一种 * 的buffer
,则以下情况成立:假设所指向类型的
sizeof
最多为300
,则4.、5.和6.都是允许的。1.、2.和3.:在上述条件下,这些是允许的,并且假设您实际上以4.、5.或6. * 中的方式写入缓冲区,首先匹配类型 *。
请注意,您可以在
std::launder
的帮助下解决new
案例中的问题,使其等效于malloc
案例。还要注意,
malloc
的情况只适用于malloc
被指定为隐式创建隐式生存期类型的对象,并返回一个指针,指向这些创建的对象中合适的一个。所有标量类型都是隐式生存期类型,这意味着您列出的所有类型也是。使用placement-new来创建要显式存储在缓冲区中的对象会更容易避免错误,placement-new返回一个指向新创建的对象的指针,您可以使用该指针而无需任何强制转换。
这些都不允许用一种类型写入缓冲区,然后用另一种类型阅读,或者用不同类型写入同一个缓冲区位置。如果没有placement-new或类似的东西介入来改变类型,那么这总是会以某种方式违反别名(并重新初始化该值!)。对于不同类型的位表示之间的强制转换,请使用
std::bit_cast
。(也许在C++23中std::start_lifetime_as
也很有用。)