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