【发布时间】:2021-06-13 02:56:25
【问题描述】:
(免责声明:在这一点上,这主要是学术兴趣。)
想象一下我有这样一个外部接口,也就是我不控制它的代码:
// Provided externally: Cannot (easily) change this:
// fill buffer with n floats:
void data_source_external(float* pDataOut, size_t n);
// send n data words from pDataIn:
void data_sink_external(const uint32_t* pDataIn, size_t n);
是否可以在标准 C++ 中在这两个接口之间“移动”/“流式传输”数据而无需复制?
也就是说,有什么方法可以使以下内容成为非 UB,而无需在两个正确类型的缓冲区之间复制数据?
int main()
{
constexpr size_t n = 64;
float fbuffer[n];
data_source_external(fbuffer, n);
// These hold and can be checked statically:
static_assert(sizeof(float) == sizeof(uint32_t), "same size");
static_assert(alignof(float) == alignof(uint32_t), "same alignment");
static_assert(std::numeric_limits<float>::is_iec559 == true, "IEEE 754");
// This is clearly UB. Any way to make this work without copying the data?
const uint32_t* buffer_alias = static_cast<uint32_t*>(static_cast<void*>(fbuffer));
// **Note**:
// + reinterpret_cast would also be UB.
data_sink_external(buffer_alias, n);
// ...
据我所知,以下将是定义的行为,至少在严格别名方面:
...
uint32_t ibuffer[n];
std::memcpy(ibuffer, fbuffer, n * sizeof(uint32_t));
data_sink_external(ibuffer, n);
但鉴于ibuffer 与fbuffer 具有完全相同的位,这似乎很疯狂。
或者我们会expect optimizing compilers to optimize 甚至这个副本吗? (在一个现已删除的类似评论的答案中,用户发布了一个godbolt link,这似乎表明,至少乍一看,clang 11 确实能够优化 memcpy。)
【问题讨论】:
标签: c++ arrays language-lawyer strict-aliasing