简体   繁体   English

使用指向 C/C++ 中未对齐的 memory 地址的指针访问结构是否安全?

[英]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;

I have a memory buffer composed with some header bytes and a struct.我有一个 memory 缓冲区,由一些 header 字节和一个结构组成。 The struct is memcpy to this memory buffer.该结构是此 memory 缓冲区的 memcpy。 I have to modify some fields in this embeded struct, as demostrated above.我必须修改这个嵌入结构中的一些字段,如上所示。

My questions are:我的问题是:

  1. Is this a safe access on x86-64?这是 x86-64 上的安全访问吗? How about other platforms?其他平台呢?

  2. memcpy to a local struct, modify it and copy it back is surely OK, but it seems wasteful. memcpy到本地结构,修改并复制回来肯定可以,但似乎很浪费。 Is there a way to check if ptr is properly aligned for safe-access to the struct?有没有办法检查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. 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. The question is not whether your target architecture (x86-64 or other) supports misaligned access but whether your C or C++ implementation, particularly the compiler, supports it.问题不在于您的目标架构(x86-64 或其他)是否支持未对齐访问,而在于您的 C 或 C++ 实现,尤其是编译器是否支持它。

Looking at your sample code, I suspect it is a proxy for copying data into a buffer from a network or file or other source, then attempting to interpret part of that data as a desired type, possibly after inspecting a header in the received data to determine the type and/or the location of the subject data.查看您的示例代码,我怀疑它是将数据从网络或文件或其他来源复制到缓冲区中的代理,然后尝试将部分数据解释为所需的类型,可能是在检查收到的数据中的 header 之后确定主题数据的类型和/或位置。 If so, you should describe the original situation, because the proxy code you showed is insufficient.如果是这样,你应该描述一下原来的情况,因为你显示的代理代码是不够的。

When reading raw data as bytes from a network or file, it is preferable to read the data directly into the desired structure.从网络或文件中以字节形式读取原始数据时,最好将数据直接读取到所需的结构中。 Ideally, the communication protocol would be specified to align the data as needed so that no further manipulation is needed once the data is received into an aligned buffer.理想情况下,将指定通信协议以根据需要对齐数据,以便一旦将数据接收到对齐的缓冲区中就不需要进一步的操作。 In C, unions may help deal with issues of aliasing one type of data as another.在 C 中,联合可能有助于处理将一种类型的数据混叠为另一种类型的问题。

Failing the direct-into-structure method, memcpy may be used, and it may not be as inefficient as you think because the memcpy method results in code with well-defined behavior and then the compiler often can, given sufficient visibility to the relevant parts of the code, optimize the assembly it generates so that no actual memcpy occurs.如果直接进入结构方法失败,则可以使用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). 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).

In C at least, dynamically allocated memory can be filled with data using a character type and then accessed as another type following rules regarding “effective types.”至少在 C 中,动态分配的 memory 可以使用字符类型填充数据,然后按照有关“有效类型”的规则作为另一种类型访问。 However, certain rules about aliasing must be followed, and this does not enable accessing incorrectly aligned data (absent use of the extensions mentioned above).但是,必须遵循有关别名的某些规则,这不能访问不正确对齐的数据(不使用上述扩展)。

Any pointer punning is dangerous as it possible break the strict-aliasing rules.任何指针双关都是危险的,因为它可能违反严格的别名规则。

You need to use memcpy .您需要使用memcpy Most optimizing compilers know memcpy very well and usually do not emit the actual call to the 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

Some OS have memory alignment requirements, if I remember correctly Solaris has a requirement that memory be aligned on 8 byte boundaries.有些操作系统有 memory alignment 要求,如果我没记错的话,Solaris 要求 memory 在 8 字节边界上对齐。 The OS will throw an error if this requirement isn't met如果不满足此要求,操作系统将抛出错误

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C++ 动态内存 // 销毁指针指向的内存 - C++ Dynamic Memory // Destroying memory pointed by pointer c ++:指针值不同于所指向变量的地址 - c++: pointer value different than address of the pointed variable 使用 C 在 ARM9 上未对齐的 memory 访问异常的解决方法是什么? - What is the workaround for unaligned memory access exception on ARM9 using C? 使用数组指针的C ++访问类struct成员 - C++ access class struct member using an array pointer 解引用指针并存储对指向数据的引用,然后获取引用地址并对其执行指针运算。 c++ - Dereferencing pointer and storing reference to the pointed data, then getting address of reference and performing pointer arithmetic on it. c++ C ++读取内存地址/指针和偏移量 - C++ Read Memory Address / Pointer & Offset C ++:通过指针访问struct的成员 - C++: Access members of struct via a pointer C ++复制指针指向的数据 - C++ Copy data pointed at by pointer C ++:指针元素的向量是否会在销毁时自动释放每个指针所指向的动态内存? - C++: Does vector of pointer elements automatically deallocate dynamic memory pointed by each pointer upon destruction? C++,如何用指向特定地址的指针访问 - C++, how to access with a pointer to a specific address
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM