[英]Is it safe to access a struct using pointer pointed to unaligned memory address in C/C++?
struct CustomData
{
char flag;
int count;
double value;
};
CustomData custom_data{};
char *buf = new char[sizeof(CustomData) + 3];
memcpy(buf + 3, &custom_data, sizeof(CustomData));
CustomData* ptr = (CustomData *)(buf + 3);
ptr->count = 10;
ptr->value = 20.0;
我有一个 memory 缓冲区,由一些 header 字节和一个结构组成。 该结构是此 memory 缓冲区的 memcpy。 我必须修改这个嵌入结构中的一些字段,如上所示。
我的问题是:
这是 x86-64 上的安全访问吗? 其他平台呢?
memcpy
到本地结构,修改并复制回来肯定可以,但似乎很浪费。 有没有办法检查ptr
是否正确对齐以安全访问结构?
Neither the C nor the C++ standards define the behavior of accessing memory without the alignment required for the lvalue type, nor even of converting a pointer to another pointer type when the pointer value does not have the alignment required for the destination type. 问题不在于您的目标架构(x86-64 或其他)是否支持未对齐访问,而在于您的 C 或 C++ 实现,尤其是编译器是否支持它。
查看您的示例代码,我怀疑它是将数据从网络或文件或其他来源复制到缓冲区中的代理,然后尝试将部分数据解释为所需的类型,可能是在检查收到的数据中的 header 之后确定主题数据的类型和/或位置。 如果是这样,你应该描述一下原来的情况,因为你显示的代理代码是不够的。
从网络或文件中以字节形式读取原始数据时,最好将数据直接读取到所需的结构中。 理想情况下,将指定通信协议以根据需要对齐数据,以便一旦将数据接收到对齐的缓冲区中就不需要进一步的操作。 在 C 中,联合可能有助于处理将一种类型的数据混叠为另一种类型的问题。
如果直接进入结构方法失败,则可以使用memcpy
,它可能不会像您想象的那样低效,因为memcpy
方法会生成具有明确行为的代码,然后编译器通常可以,只要对相关部分有足够的可见性代码,优化它生成的程序集,以便不会发生实际的memcpy
。
Failing that, some compilers have various extensions to the C and C++ standards that let you define structure types without alignment requirements and to access memory using arbitrary types (supporting aliasing character arrays as other types).
至少在 C 中,动态分配的 memory 可以使用字符类型填充数据,然后按照有关“有效类型”的规则作为另一种类型访问。 但是,必须遵循有关别名的某些规则,这不能访问不正确对齐的数据(不使用上述扩展)。
任何指针双关都是危险的,因为它可能违反严格的别名规则。
您需要使用memcpy
。 大多数优化编译器都非常了解memcpy
并且通常不会发出对memcpy
的实际调用:
typedef struct CustomData
{
char flag;
int count;
double value;
}CustomData;
CustomData *foo(int val, double d)
{
char *buf = new char[sizeof(CustomData) + 3];
CustomData cd;
cd.count = val;
cd.value = d;
memcpy(buf + 3, &cd, sizeof(cd));
return (CustomData *)buf;
}
foo(int, double):
push rbp
mov ebp, edi
mov edi, 19
push rbx
sal rbp, 32
movq rbx, xmm0
sub rsp, 8
call operator new[](unsigned long)
mov QWORD PTR [rax+3], rbp
mov QWORD PTR [rax+11], rbx
add rsp, 8
pop rbx
pop rbp
ret
有些操作系统有 memory alignment 要求,如果我没记错的话,Solaris 要求 memory 在 8 字节边界上对齐。 如果不满足此要求,操作系统将抛出错误
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.