Malloc 和 memcpy struct 加数组
Malloc and memcpy struct plus array
我正在寻找一个更好的标题,如果它令人困惑,我深表歉意。
我正在通过串行端口读取一条二进制消息。该消息包含一个常量 8 字节 header 和一个动态消息长度(取决于在 8 字节 header 中定义的消息类型)。
我正在尝试创建一个函数,该函数returns此消息与使用 malloc 分配的数组。
我更改了一些 variable/member 名称只是为了更清楚
示例:
#include <stdlib.h>
#include <stdio.h>
typedef struct MyMessageHeader {
uint8_t byte1, byte2, byte3, byte4, byte5, byte6, byte7,
} MyMessageHeader;
// I could have up to 100 different message types, but they all contain
// the same header, so trying to make a message type with a header and array pointer
typedef struct MyMessage {
MyMessageHeader header;
uint8_t* data;
} MyMessage;
// Function to copy a raw byte array that is read from the serial port into
// a MyMessage object
MyMessage* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Somehow we have determined in rawBytes that this message contains 12 bytes of data
// plus the 8 bytes which is the header
MyMessage* ret_msg = malloc(20);
// This is where things go wrong and I get segmentation faults. Likely due to
// my misunderstanding of malloc.
// Copy the rawBytes into MyMessage. Assuming the first 8 bytes of rawBytes goes
// into MyMessageHeader, and the last 12 bytes go into data
memcpy(ret_msg, rawBytes, 20);
}
int main() {
uint8_t raw_bytes[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
MyMessage* my_msg = FunctionThatIsNotWorking(raw_bytes);
// Expecting now but this doesnt work
my_msg->header.byte1 == 1;
my_msg->header.byte2 == 2;
my_msg->header.byte3 == 3;
// ...
// first byte of data should be the 9th byte in raw_bytes
my_msg->data[0] == 9;
my_msg->data[1] == 10;
}
我在这里缺少什么,或者我的 mis-understanding 是什么?
我怀疑在欺骗你(双关语)是 structure padding
建议:
将数据直接从您的设备读取到本地缓冲区。使缓冲区至少与预期的最大消息一样长。
阅读header
执行你的"malloc",最后
将缓冲区中的数据解压到你
好的:这是我的建议:
/*
* SAMPLE OUTPUT:
* sizeof(*my_msg)= 16
* header: 01 02 03 04 05 06 07 08
* data: 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14
*/
#include <stdio.h>
#include <stdint.h> // unit8_t
#include <stdlib.h> // malloc()
#include <string.h> // memcpy ()
typedef struct MyMessage {
uint8_t header[8]; // 8 bytes (you said) for header; message length unknown.
uint8_t* data; // Here, you're only allocating space for a pointer (e.g. 4 bytes)
} MyMessage_t;
MyMessage_t* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Let's assume rawBytes contains header + data
// Parse the header, determine message type, and determine message length
// ... TBD ...
// Allocate your struct
MyMessage_t* ret_msg = malloc(sizeof (struct MyMessage));
// Now allocate space for your *data* (let's assume this particular message has 12 bytes)
ret_msg->data = malloc(12);
// Copy your header (from rawBytes)
memcpy(&ret_msg->header, rawBytes, 8);
// Copy the data (starting on the ninth byte; assume the data is contiguous)
memcpy(ret_msg->data, &rawBytes[8], 12);
// Return the completed record
return ret_msg;
}
int main() {
int i;
// Create some dummy data
uint8_t raw_bytes[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
MyMessage_t* my_msg = FunctionThatIsNotWorking(raw_bytes);
printf ("sizeof(*my_msg)= %ld\n", sizeof(*my_msg));
printf ("header: ");
for (i=0; i<sizeof(my_msg->header); i++) {
printf("%02x ", my_msg->header[i]);
}
printf ("\ndata: ");
for (i=0; i<12; i++) {
printf("%02x ", my_msg->data[i]);
}
printf ("\n");
return 0;
}
我想表达的意思是,编译器为您的结构提供的字节布局不一定符合您的预期。字段中经常有"extra spacing",以确保对齐。
如果您在发送端使用结构(在构建消息时),接收方的数据布局不一定与发送方的布局相匹配。
因此,您通常需要明确 "pack" 和 "unpack" 在不同 hosts/different 平台之间来回发送的消息。
我认为重点是您从未为您的数据分配 space。这是真的 :) 我希望上面的例子有所帮助。
最后,在大多数情况下,在您实际阅读 header 之前,消息的长度是未知的。我的示例也处理了这种情况。
如果您只想将数据传递回调用者(我的示例同时复制 header 和数据),您可能需要在结构中添加一个 "message length" 字段。
始终尝试使用 "sizeof" 运算符,而不是 hard-coding "magic numbers"。下一个最好的事情是声明常量(例如 #define DATA_LENGTH 12
)。
'希望对您有所帮助!
再举一个例子。
假设您知道您的消息数据总是正好是 12 个字节。我们仍然假设您希望 header 字段为 8 个字节。你可以这样做:
...
typedef struct MyMessage {
uint8_t header[8]; // 8 bytes (you said) for header
uint8_t data[12]; // This allocates 12 bytes
} MyMessage_t;
...
MyMessage_t* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Let's assume rawBytes contains header + data
// Parse the header, determine message type, and determine message length
// ... TBD ...
// Allocate your struct
MyMessage_t* ret_msg = malloc(sizeof (*ret_msg));
// Copy directly from rawBytes
memcpy(ret_msg, rawBytes, sizeof (*ret_msg));
// Return the completed record
return ret_msg;
}
我正在寻找一个更好的标题,如果它令人困惑,我深表歉意。
我正在通过串行端口读取一条二进制消息。该消息包含一个常量 8 字节 header 和一个动态消息长度(取决于在 8 字节 header 中定义的消息类型)。
我正在尝试创建一个函数,该函数returns此消息与使用 malloc 分配的数组。
我更改了一些 variable/member 名称只是为了更清楚 示例:
#include <stdlib.h>
#include <stdio.h>
typedef struct MyMessageHeader {
uint8_t byte1, byte2, byte3, byte4, byte5, byte6, byte7,
} MyMessageHeader;
// I could have up to 100 different message types, but they all contain
// the same header, so trying to make a message type with a header and array pointer
typedef struct MyMessage {
MyMessageHeader header;
uint8_t* data;
} MyMessage;
// Function to copy a raw byte array that is read from the serial port into
// a MyMessage object
MyMessage* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Somehow we have determined in rawBytes that this message contains 12 bytes of data
// plus the 8 bytes which is the header
MyMessage* ret_msg = malloc(20);
// This is where things go wrong and I get segmentation faults. Likely due to
// my misunderstanding of malloc.
// Copy the rawBytes into MyMessage. Assuming the first 8 bytes of rawBytes goes
// into MyMessageHeader, and the last 12 bytes go into data
memcpy(ret_msg, rawBytes, 20);
}
int main() {
uint8_t raw_bytes[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
MyMessage* my_msg = FunctionThatIsNotWorking(raw_bytes);
// Expecting now but this doesnt work
my_msg->header.byte1 == 1;
my_msg->header.byte2 == 2;
my_msg->header.byte3 == 3;
// ...
// first byte of data should be the 9th byte in raw_bytes
my_msg->data[0] == 9;
my_msg->data[1] == 10;
}
我在这里缺少什么,或者我的 mis-understanding 是什么?
我怀疑在欺骗你(双关语)是 structure padding
建议:
将数据直接从您的设备读取到本地缓冲区。使缓冲区至少与预期的最大消息一样长。
阅读header
执行你的"malloc",最后
将缓冲区中的数据解压到你
好的:这是我的建议:
/*
* SAMPLE OUTPUT:
* sizeof(*my_msg)= 16
* header: 01 02 03 04 05 06 07 08
* data: 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14
*/
#include <stdio.h>
#include <stdint.h> // unit8_t
#include <stdlib.h> // malloc()
#include <string.h> // memcpy ()
typedef struct MyMessage {
uint8_t header[8]; // 8 bytes (you said) for header; message length unknown.
uint8_t* data; // Here, you're only allocating space for a pointer (e.g. 4 bytes)
} MyMessage_t;
MyMessage_t* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Let's assume rawBytes contains header + data
// Parse the header, determine message type, and determine message length
// ... TBD ...
// Allocate your struct
MyMessage_t* ret_msg = malloc(sizeof (struct MyMessage));
// Now allocate space for your *data* (let's assume this particular message has 12 bytes)
ret_msg->data = malloc(12);
// Copy your header (from rawBytes)
memcpy(&ret_msg->header, rawBytes, 8);
// Copy the data (starting on the ninth byte; assume the data is contiguous)
memcpy(ret_msg->data, &rawBytes[8], 12);
// Return the completed record
return ret_msg;
}
int main() {
int i;
// Create some dummy data
uint8_t raw_bytes[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
MyMessage_t* my_msg = FunctionThatIsNotWorking(raw_bytes);
printf ("sizeof(*my_msg)= %ld\n", sizeof(*my_msg));
printf ("header: ");
for (i=0; i<sizeof(my_msg->header); i++) {
printf("%02x ", my_msg->header[i]);
}
printf ("\ndata: ");
for (i=0; i<12; i++) {
printf("%02x ", my_msg->data[i]);
}
printf ("\n");
return 0;
}
我想表达的意思是,编译器为您的结构提供的字节布局不一定符合您的预期。字段中经常有"extra spacing",以确保对齐。
如果您在发送端使用结构(在构建消息时),接收方的数据布局不一定与发送方的布局相匹配。
因此,您通常需要明确 "pack" 和 "unpack" 在不同 hosts/different 平台之间来回发送的消息。
我认为重点是您从未为您的数据分配 space。这是真的 :) 我希望上面的例子有所帮助。
最后,在大多数情况下,在您实际阅读 header 之前,消息的长度是未知的。我的示例也处理了这种情况。
如果您只想将数据传递回调用者(我的示例同时复制 header 和数据),您可能需要在结构中添加一个 "message length" 字段。
始终尝试使用 "sizeof" 运算符,而不是 hard-coding "magic numbers"。下一个最好的事情是声明常量(例如 #define DATA_LENGTH 12
)。
'希望对您有所帮助!
再举一个例子。
假设您知道您的消息数据总是正好是 12 个字节。我们仍然假设您希望 header 字段为 8 个字节。你可以这样做:
...
typedef struct MyMessage {
uint8_t header[8]; // 8 bytes (you said) for header
uint8_t data[12]; // This allocates 12 bytes
} MyMessage_t;
...
MyMessage_t* FunctionThatIsNotWorking(uint8_t* rawBytes) {
// Let's assume rawBytes contains header + data
// Parse the header, determine message type, and determine message length
// ... TBD ...
// Allocate your struct
MyMessage_t* ret_msg = malloc(sizeof (*ret_msg));
// Copy directly from rawBytes
memcpy(ret_msg, rawBytes, sizeof (*ret_msg));
// Return the completed record
return ret_msg;
}