c ++制作具有未知大小数组的结构(内存位置完好无损)以传递缓冲区数据
c++ making struct with unknown size array (with memory location intact) for passing buffer data
所以,我需要以特定方式布置内存:
struct aPacketWithMoreData{
double x;
int16 h;
int16 noNeedToBePassedToTheBuffer;
double y;
}
struct aPacket{
double x;
double y;
int16 h;
}
struct bufferData{
int32 something;
uint64 anotherthing;
aPacket arrayOfData[]; //with unknown size or runtime size
float32 somethingThatEndThis;
int16 withMaybeWeirdSizeAlinement;
}
然后我有一个 aPacketWithMoreData 数组。我需要制作一个临时缓冲区数据,以便我可以调用 API (非常慢)一次来复制缓冲区。做这个的最好方式是什么? (请注意,存储 std::vector 没有帮助,因为 std::vector 实际上只是一个指向数组的指针,而在 API 的另一端,它将无法删除-参考那个。)
我知道在 C++ 中你可以这样做:(link: https://en.cppreference.com/w/c/language/struct)
struct s{
int a;
float b;
double c[]; //array of unknown size
}
...
void function(uint numberOfC) {
struct s objectName = malloc(sizeof (struct s) + sizeof(double)*numberOfC);
...
}
但我相信这是为了 c 的可移植性。当数组位于中间时(缓冲区结构需要),这也不起作用。那么除了像下面这样破解它之外,还有更好的方法吗?
void function(uint number) {
char* buffer = new char[sizeof(int32)+sizeof(uint64)+sizeof(float32)+sizeof(int16)+sizeof(aPacket)*number];
*(int32*)(buffer[0]) = returnsInt32();
*(uint64*)(buffer[sizeof(int32)]) = returnsuint64();
...
size_t offset = sizeof(int32)+sizeof(uint64);
for (uint i=0; i<number; i++) {
aPacketWithMoreData& obj = aVector[i]; //inore the possible out of bound for now
*((aPacket*)(buffer[offset])+i) = aPacket(obj.x,obj.y,obj.h);
}
...
AnAPI.passData(buffer, sizeof(buffer));
}
编辑:修复了字符数组问题。
这不是为了与 C 兼容,而是标准之外的扩展。无法表示未确定的数组大小,至少在标准中没有定义。在 C 或 C++ 中,类型在编译时是已知的,这意味着它的内存布局是已知的:类型的大小和每个元素的 offsets\memory 位置。
Windows 等一些平台专门调整了 C++ 编译器以支持现有 API,但这不是标准保证,但在更高版本中你不能使用 []
,而是使用 [1]
。典型的 Windows API 结构,变量 length:
typedef struct _SYMBOL_INFO {
ULONG SizeOfStruct; // size of structure, a tradition safety measure in API
ULONG TypeIndex;
ULONG64 Reserved[2];
ULONG Index;
ULONG Size;
ULONG64 ModBase;
ULONG Flags;
ULONG64 Value;
ULONG64 Address;
ULONG Register;
ULONG Scope;
ULONG Tag;
ULONG NameLen;
ULONG MaxNameLen; // length of Name in bytes.
CHAR Name[1];
} SYMBOL_INFO;
在 C++ 中使用这种结构需要这样的东西:
// buffer for SYMBOL_INFO with string of 1024 bytes.
ULONG64 buffer[ (sizeof( SYMBOL_INFO ) + TRACE_MAX_FUNCTION_NAME_LENGTH
+ sizeof( ULONG64 ) - 1) / sizeof( ULONG64 ) ];
SYMBOL_INFO *info = new (buffer) SYMBOL_INFO {};
info->SizeOfStruct = sizeof( SYMBOL_INFO );
info->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
您的结构需要一分为二。
struct bufferData{
int32 something;
uint64 anotherthing;
uint lengthOfArray; // length of following array
aPacket arrayOfData[1]; // varadic size
};
struct bufferFooter{
float32 somethingThatEndThis;
int16 withMaybeWeirdSizeAlinement;
};
请注意 somethingThatEndThis
可能有对齐要求,所以 bufferFooter
也有。
// add number of packets to size of this buffer, by default it's one.
uint64_t *buffer = new uint64_t[ (sizeof(bufferData)+sizeof(bufferFooter)
+ (sizeof(uint64_t)-1))/sizeof(uint64_t) ];
bufferData* dptr = new (&buffer) bufferData {};
bufferData* fptr = new (&buffer[sizeof(bufferData)/sizeof(uint64_t)]) bufferFooter {};
dptr->lengthOfArray = 1;
这按 64 位字对齐结构。如果需要按 char
对齐,这可能会有点复杂,除非使用 memcpy 或平台支持自由对齐。对于从外部源“接收”这种结构,只要结构是 POD,reinterpret_cast
就是一个合法的工具。
如果这些结构是某些二进制文件结构或网络协议的一部分,极度需要快速提取数据,通常的做法是添加 header,这将包括那些“游荡”结构超出变量数组的偏移量. .bmp 或 .png 文件的结构就是很好的例子。在提取时间不成问题的情况下,许多协议转移到 xml-like 结构、二进制表示或文本。
所以,我需要以特定方式布置内存:
struct aPacketWithMoreData{
double x;
int16 h;
int16 noNeedToBePassedToTheBuffer;
double y;
}
struct aPacket{
double x;
double y;
int16 h;
}
struct bufferData{
int32 something;
uint64 anotherthing;
aPacket arrayOfData[]; //with unknown size or runtime size
float32 somethingThatEndThis;
int16 withMaybeWeirdSizeAlinement;
}
然后我有一个 aPacketWithMoreData 数组。我需要制作一个临时缓冲区数据,以便我可以调用 API (非常慢)一次来复制缓冲区。做这个的最好方式是什么? (请注意,存储 std::vector 没有帮助,因为 std::vector 实际上只是一个指向数组的指针,而在 API 的另一端,它将无法删除-参考那个。)
我知道在 C++ 中你可以这样做:(link: https://en.cppreference.com/w/c/language/struct)
struct s{
int a;
float b;
double c[]; //array of unknown size
}
...
void function(uint numberOfC) {
struct s objectName = malloc(sizeof (struct s) + sizeof(double)*numberOfC);
...
}
但我相信这是为了 c 的可移植性。当数组位于中间时(缓冲区结构需要),这也不起作用。那么除了像下面这样破解它之外,还有更好的方法吗?
void function(uint number) {
char* buffer = new char[sizeof(int32)+sizeof(uint64)+sizeof(float32)+sizeof(int16)+sizeof(aPacket)*number];
*(int32*)(buffer[0]) = returnsInt32();
*(uint64*)(buffer[sizeof(int32)]) = returnsuint64();
...
size_t offset = sizeof(int32)+sizeof(uint64);
for (uint i=0; i<number; i++) {
aPacketWithMoreData& obj = aVector[i]; //inore the possible out of bound for now
*((aPacket*)(buffer[offset])+i) = aPacket(obj.x,obj.y,obj.h);
}
...
AnAPI.passData(buffer, sizeof(buffer));
}
编辑:修复了字符数组问题。
这不是为了与 C 兼容,而是标准之外的扩展。无法表示未确定的数组大小,至少在标准中没有定义。在 C 或 C++ 中,类型在编译时是已知的,这意味着它的内存布局是已知的:类型的大小和每个元素的 offsets\memory 位置。
Windows 等一些平台专门调整了 C++ 编译器以支持现有 API,但这不是标准保证,但在更高版本中你不能使用 []
,而是使用 [1]
。典型的 Windows API 结构,变量 length:
typedef struct _SYMBOL_INFO {
ULONG SizeOfStruct; // size of structure, a tradition safety measure in API
ULONG TypeIndex;
ULONG64 Reserved[2];
ULONG Index;
ULONG Size;
ULONG64 ModBase;
ULONG Flags;
ULONG64 Value;
ULONG64 Address;
ULONG Register;
ULONG Scope;
ULONG Tag;
ULONG NameLen;
ULONG MaxNameLen; // length of Name in bytes.
CHAR Name[1];
} SYMBOL_INFO;
在 C++ 中使用这种结构需要这样的东西:
// buffer for SYMBOL_INFO with string of 1024 bytes.
ULONG64 buffer[ (sizeof( SYMBOL_INFO ) + TRACE_MAX_FUNCTION_NAME_LENGTH
+ sizeof( ULONG64 ) - 1) / sizeof( ULONG64 ) ];
SYMBOL_INFO *info = new (buffer) SYMBOL_INFO {};
info->SizeOfStruct = sizeof( SYMBOL_INFO );
info->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
您的结构需要一分为二。
struct bufferData{
int32 something;
uint64 anotherthing;
uint lengthOfArray; // length of following array
aPacket arrayOfData[1]; // varadic size
};
struct bufferFooter{
float32 somethingThatEndThis;
int16 withMaybeWeirdSizeAlinement;
};
请注意 somethingThatEndThis
可能有对齐要求,所以 bufferFooter
也有。
// add number of packets to size of this buffer, by default it's one.
uint64_t *buffer = new uint64_t[ (sizeof(bufferData)+sizeof(bufferFooter)
+ (sizeof(uint64_t)-1))/sizeof(uint64_t) ];
bufferData* dptr = new (&buffer) bufferData {};
bufferData* fptr = new (&buffer[sizeof(bufferData)/sizeof(uint64_t)]) bufferFooter {};
dptr->lengthOfArray = 1;
这按 64 位字对齐结构。如果需要按 char
对齐,这可能会有点复杂,除非使用 memcpy 或平台支持自由对齐。对于从外部源“接收”这种结构,只要结构是 POD,reinterpret_cast
就是一个合法的工具。
如果这些结构是某些二进制文件结构或网络协议的一部分,极度需要快速提取数据,通常的做法是添加 header,这将包括那些“游荡”结构超出变量数组的偏移量. .bmp 或 .png 文件的结构就是很好的例子。在提取时间不成问题的情况下,许多协议转移到 xml-like 结构、二进制表示或文本。