[英]C vs C++ placing structs in unsigned char buffer
C 是否有任何類似於 C++ 的東西,其中可以將結構放置在無符號字符緩沖區中,就像在 C++ 中所做的那樣,如標准sec 所示。 6.7.2
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
在 C 中,我當然可以將一個事物結構(或如上所示的 int)memcpy 到一個無符號字符緩沖區中,但隨后使用指向該結構的指針會遇到嚴格的別名違規; 緩沖區具有不同的聲明類型。
因此,假設有人想在 C 中復制上述 C++ 中的第二行。 一個人會做這樣的事情
#include<string.h>
#include<stdio.h>
struct Buffer {
unsigned char data[sizeof(int)];
};
int main()
{
struct Buffer b;
int n = 5;
int* p = memcpy(&b.data,&n,sizeof(int));
printf("%d",*p); // aliasing violation here as unsigned char is accessed as int
return 0;
}
通常建議使用聯合,即union Buffer {int i;unsigned char b[sizeof(int)]};
但是,如果緩沖區的目的是充當存儲(即在其中放置不同大小的類型,通過將指針推進到緩沖區中的空閑部分 + 可能更多一些以進行正確對齊),那么這並不是那么好。
您是否嘗試過使用union
?
#include <string.h>
#include <stdio.h>
union Buffer {
int int_;
double double_;
long double long_double_;
unsigned char data[1];
};
int main() {
union Buffer b;
int n = 5;
int *p = memcpy(&b.data, &n, sizeof(int));
printf("%d", *p); // aliasing violation here as unsigned char is accessed as int
return 0;
}
Buffer
根據 alignment 要求最大的類型對齊data
成員。
是的,由於嚴格的別名規則,這是不可能的。 因為不可能編寫符合標准的malloc()
。
您的緩沖區未對齊 - 需要添加 stdalign.h 中的stdalign.h
alignas(int)
。
如果要防止編譯器優化,請:
-fno-strict-aliasing
編譯,或使用volatile
// mybuffer.c
#include <stdalign.h>
alignas(int) unsigned char buffer[sizeof(int)];
void *getbuffer() { return buffer; }
// main.c
#include <string.h>
#include <stdio.h>
#include "mybuffer.h"
int main() {
void *data = getbuffer();
// int *p = new (au.data) int; // OK, au.data provides storage
int *p = data;
// char *c = new (au.data) char(); // OK, ends lifetime of *p
char *c = data;
*c = 0;
// char *d = new (au.data + 1) char();
char *d = (char*)data + 1;
*d = 0;
return *c + *d;
}
6.5p6 中有效類型定義的編寫方式,不清楚它在所有極端情況下應該意味着什么——可能是因為委員會成員之間從未就如何處理所有極端情況達成共識。 缺陷報告通常會增加混亂而不是清晰,因為當標准和缺陷報告都沒有指定要設置或更改哪些操作時,它們使用諸如工會的“活躍成員”之類的術語。
如果想使用 object 或 static 或自動持續時間,就好像它是沒有聲明類型的緩沖區一樣,一種安全的方法應該是執行以下操作:
void volatile *volatile dummy_vp;
void test(void)
{
union {
char dat[1000];
unsigned long force_alignment;
} buffer;
void *volatile launder = buffer.dat;
dummy_vp = &launder;
void *storage_blob = launder;
...
}
除非實現不遺余力地測試launder
的讀取是否碰巧產生了與buffer.dat
匹配的地址,否則它將無法知道該地址處的 object 是否具有聲明的類型。 如果地址恰好與buffer.dat
的地址匹配,標准中的任何內容都不會禁止實現無意義的行為,但是性能改進證明檢查成本合理的情況不太常見,編譯器無法嘗試這種“優化” ”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.