C++严格的混叠冲突



我有一个(char*)缓冲区。我可以做以下事情吗:

  1. int8_t i8 = *(int8_t*)buffer;

  2. int16_t i16 = *(int16_t*)buffer;

  3. float f = *(float*)buffer;

  4. int8_t i = 22; *(int8_t*)buffer = i

  5. int16_t i = 25; *(int16_t*)buffer = i

  6. float f = 16.4; *(float*)buffer = f

编辑:让我们假设缓冲区是通过以下方式之一创建的:

  1. char* buffer = new char[300 * sizeof(char)];
  2. char* buffer = (char*)malloc(300 * sizeof(char));

对于带有new的版本,它们都不能保证在所有可能的实现上都没有未定义的行为:

如果int8_t不是charsigned char(但在我所知的所有平台上都是),则
  1. 是一种混叠冲突(因此是未定义的行为)。如果在两者之间不给buffer[0]赋值,它也会读取一个不确定的值,这也会导致未定义的行为。

  2. 如果int16_t不是charsigned char,则也是一种混叠冲突,这在任何具有CHAR_BIT == 8的普通平台上都是不可能的。buffer[0]的初始化再次丢失。

  3. 保证是混叠冲突。

  4. 与1相同。减去不确定价值问题。

  5. 与2相同。减去不确定价值问题。

  6. 与3相同。


对于带有malloc的版本,假设您只访问过带有buffer,则以下情况成立:您列出的类型中只有一种:

4.、5.和6。假设指向类型的CCD_ 21至多为CCD_。

1.,2。和3.:在上述条件下,这些都是允许的,并且假设您实际上以4.、5.中的方式写入缓冲区。或6首先匹配类型


请注意,您可以在std::launder的帮助下修复new案例中的问题,使其等效于malloc案例。

还要注意,malloc的情况之所以有效,是因为malloc被指定为隐式创建隐式生存期类型的对象,并返回指向这些创建的对象中合适对象的指针。所有标量类型都是隐式生存期类型,这意味着您列出的所有类型也是。

通过使用placementnew来创建要显式存储在缓冲区中的对象,在这里不犯错误会容易得多。placement new返回一个指向新创建的对象的指针,您可以在不进行任何强制转换的情况下使用该对象。

所有这些都不允许用一种类型写入缓冲区,然后用另一种类型读取,或者用不同类型写入同一缓冲区位置。如果没有新的或类似的放置来更改类型(并重新初始化值!),那么无论如何,这都将是一种混叠冲突。对于不同类型的位间转换表示,请改用std::bit_cast。(也许C++23中的std::start_lifetime_as也有帮助。)

最新更新