C++严格别名冲突

q9yhzks0  于 2023-01-18  发布在  其他
关注(0)|答案(1)|浏览(164)

我有一个(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
    EDIT:让我们假设缓冲区是通过以下方式之一创建的:
  7. char* buffer = new char[300 * sizeof(char)];
  8. char* buffer = (char*)malloc(300 * sizeof(char));
mf98qq94

mf98qq941#

对于使用new的版本,不能保证它们在所有可能的实现中都有未定义的行为:
1.如果int8_t不是charsigned char(但在我所知道的所有平台上都是这样),则是一个别名冲突(因此是未定义的行为)。如果您没有为buffer[0]赋值,则它也会阅读一个不确定的值,这也会导致未定义的行为。
1.如果int16_t不是charsigned 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也很有用。)

相关问题