我正在将其作为学习练习。我正在研究的C++书籍将缓冲区作为一种易于操作和流式传输的结构。一切似乎都很好,直到我尝试使用数组(body)并在分配值之后查看缓冲区中的二进制数据。它与我的期望不符。
#include <iostream>
#include <bitset>
#include <netinet/in.h>
using namespace std;
struct dataStruct
{
uint32_t header;
uint32_t *body;
};
int main(int argc, char* argv[])
{
int size, streamSize;
// 4 bytes per size + 4 bytes for header
size = 1;
streamSize = (size * 4) + 4;
// Create a stream of bytes of appropriate size
uint8_t *buffer = new uint8_t[streamSize];
// Cast stream as structure
dataStruct *sStream = (dataStruct *)buffer;
// Populate structure with nice 101010... binary patterns
sStream->header = 2863311530;
sStream->body = new uint32_t[1];
sStream->body[0] = 2863311530;
cout << "Struct: " << sStream->header << ", " << sStream->body[0] << endl;
// Look at raw data in stream
for (int i=0; i<sizeof(buffer); i++)
{
std::bitset<8> x(buffer[i]);
cout << "[" << i << "]->" << x << endl;
}
return 0;
}
输出为:
Struct: 2863311530, 2863311530
[0]->10101010
[1]->10101010
[2]->10101010
[3]->10101010
[4]->00000000
[5]->00000000
[6]->00000000
[7]->00000000
为什么索引4-7与0-3不同? sStream-> header和sStream-> body都包含相同的值。它们被映射到缓冲区。这是因为body是数组吗?如果是这样,在使用数组时,我将如何操作流以使其工作?
谢谢
最佳答案
您在以下位置使用未初始化的可变size
:
streamSize = (size * 4) + 4;
此后取决于
streamSize
的所有内容都是可疑的,并且是导致未定义行为的原因。更新
即使在将
size
初始化为1
之后,仍然存在问题。让我逐步讲解代码以及它如何影响您分配的内存。执行该行之后:
uint8_t *buffer = new uint8_t[streamSize];
你有
buffer
指向这样的内存:buffer
|
v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
执行该行之后:
dataStruct *sStream = (dataStruct *)buffer;
您的
sStream
指向相同的内存,例如:sStream
|
v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
如果您的编译器未向
dataStruct
的成员添加任何填充(最佳情况),则将具有:sStream.header sStream.body
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
如果您的编译器在
dataStream.header
中添加了填充,sStream.body
将指向其他内容。最坏的情况:您有一个64位编译器。它将32位填充添加到dataStream.header
。在这种情况下,您将拥有:sStream.header sStream.body
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
然后,当您尝试向
sStream.body
分配任何内容时,最终将使用未授权的内存,例如:sStream->body = new uint32_t[1];
最好的情况是,您有32位编译器,并且
dataStream.header
中没有添加任何填充。看起来您有一个64位编译器。即使您的编译器未在dataStream.header
中添加任何填充,如果sizeof(void*)
是64位,您仍在查看内存溢出问题,我认为您确实这样做。让我们以32位编译器的最佳情况为例,该编译器不添加任何填充,并且
sStream
的成员指向分配的内存,例如:sStream.header sStream.body
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
执行该行之后:
sStream->header = 2863311530;
内存看起来像:
sStream.header sStream.body
| |
v v
+---+---+---+---+---+---+---+---+
| 2863311530 | |
+---+---+---+---+---+---+---+---+
执行该行之后:
sStream->body = new uint32_t[1];
内存看起来像:
sStream.header sStream.body
| |
v v
+---+---+---+---+---+---+---+---+
| 2863311530 | SomeMemory |
+---+---+---+---+---+---+---+---+
SomeMemory
|
v
+---+---+---+---+
| |
+---+---+---+---+
执行该行之后:
sStream->body[0] = 2863311530;
SomeMemory
被填充,看起来像:SomeMemory
|
v
+---+---+---+---+
| 2863311530 |
+---+---+---+---+
我认为您惊讶地发现
buffer
所指向的内存看起来并不像:buffer
|
v
+---+---+---+---+---+---+---+---+
| 2863311530 | 2863311530 |
+---+---+---+---+---+---+---+---+
我希望现在知道为什么没有这样做。
关于c++ - 将缓冲区转换为结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24372555/