2016-10-03 23 views
0

试图响应another question,我提出了一个解决方案,它使用std::memcpy()将通用类型存储在char的缓冲区中。普通旧数据和`std :: memcpy`对齐问题

我的疑问是关于存储POD的可能的内存对齐问题(我知道与非POD类型,因为std::string,是非常非常危险的)。

简而言之:有与下面的程序内存对齐问题?

而且如果是这样,有可能写类似(在char缓冲区店POD值)的东西是安全的呢?如何?

#include <cstring> 
#include <iostream> 

int main() 
{ 
    char buffer[100]; 

    double d1 { 1.2 }; 

    std::memmove(buffer + 1, & d1, sizeof(double)); 

    double d2; 

    std::memmove(& d2, buffer + 1, sizeof(double)); 

    std::cout << d2 << std::endl; 

    return 0; 
} 
+0

这应该工作。一般来说,应该检查sizeof()小于固定缓冲区,但是double方法当然要小于这里使用的100。 – Gregg

+0

@Gregg - 当然;我用'100'来避免对缓冲区大小的怀疑。 – max66

回答

5

这是安全的。

[basic.types]/2:对于任何平凡复制的类型T,如果两个指针T指向不同T对象obj1obj2,其中 既不obj1也不obj2是碱基 - 类子对象,如果标的字节(1.7)构成obj1被复制到 obj2obj2随后应保持相同的值obj1

由于double是可以复制的,所以您的代码已定义良好。

3

您可以复制和从一个未对齐的缓冲区。你不能做的就是将缓冲区转换为double *,然后直接对内存中的值进行操作,作为double操作。通常这会由于对齐问题而导致错误。

+2

“*由于陷阱表示,技术上将随机字节分配给char是未定义的。*”不符合标准。 [basic.types]/2表示你可以使用'char'或'unsigned char'来轻松复制对象。 –

+0

这是标准中的一个小故障。 char允许陷阱表示,其中一个子句必须不正确。实际上,作者点头并且类型必须是无符号字符。 –

+1

没有小故障。 'char'被允许有符号或无符号。 'signed char'可能有也可能没有陷阱表示。为了使实现符合标准,如果'signed char'可以陷阱,那么'char' *一定不能被签名*。所以一个2的补码符号'char'类型是完全有效的。标准中还有其他地方有这样的要求,例如对'char'的UTF-8要求(能够在'char'和'unsigned char'之间转换任何UTF-8代码需要'char'不是陷阱)。 –