简体   繁体   English

为什么这个结构的内存副本没有按预期将字节复制到字节流?

[英]Why does this memory copy of a struct not copy bytes to byte stream as expected?

I need to serialise a struct and I am trying to do this using memcpy.我需要序列化一个结构,我正在尝试使用 memcpy 来做到这一点。 But it is not working.但它不起作用。 I can tell by looking at the byte stream - I see garbage characters.我可以通过查看字节流来判断 - 我看到了垃圾字符。 Why?为什么?

Also I get runtime error:我也得到运行时错误:

Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.运行时检查失败 #2 - 变量“地址”周围的堆栈已损坏。

What is happening and how can I fix this?发生了什么,我该如何解决?

I am using #pragma pack(push, 1) which I thought would mean there would be no padding of the structs.我正在使用#pragma pack(push, 1) ,我认为这意味着不会对结构进行填充。

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#pragma pack(push, 1)  /* padding has to be disabled for casting to struct to work at other end */
typedef struct {
    uint8_t             start_char; 
    uint8_t             msg_type;      
    uint8_t             length;     
} MSG_HEADER;

typedef struct {
    uint8_t         denomination[6];   
    uint8_t         path;    
    uint8_t         min_level; 
    uint16_t        max_level;     
    uint16_t        weight;    
    uint8_t         address;  
} CONFIG_DATA;

typedef struct {
    MSG_HEADER            header;
    uint8_t               clear_type;  
    CONFIG_DATA           config_data[12]; 
    uint8_t               system_algorithm; 
    uint8_t               max_transaction;   
} MSG_CONFIGURATION;
#pragma pack(pop) /* only affect this file */

typedef struct {
    unsigned char data[256];
    size_t length;
    int msg_type;
} TCHU_MESSAGE;

enum DRM_MESSAGE_TYPE { 
    CONFIG, CLEAR_COUNT, DISPENSE, CANCEL_TRANSACTION };

void TestCopy()
{
    MSG_CONFIGURATION config;

    config.clear_type = 0;  
    config.system_algorithm = 0;
    config.max_transaction = 17;

    const int NumItems = 12;
    const uint16_t maxLevel = 300;

    static const char* denoms[] = { "GB005A","GB005B","GB010A","GB010B",
        "GB020A","GB050A","GB050B","GB100A",
        "GB100B","GB200A", "EU100A", "EU100B" };

    const uint8_t addresses[] =     { 0, 0, 5, 5, 0, 7, 7, 8, 8, 9, 0, 0 };
    const uint8_t sorting_paths[] = { 5, 5, 4, 4, 5, 2, 2, 1, 1, 3, 0, 0 };

    for(int i = 0; i < NumItems; ++i) {
        memcpy(config.config_data[i].denomination, denoms[i], 6);
        config.config_data[i].address = addresses[i];
        config.config_data[i].path = sorting_paths[i];
        config.config_data[i].min_level = 3;
        config.config_data[i].max_level = maxLevel;
        config.config_data[i].weight = 1000;
    }

    config.header.start_char = 1;
    config.header.msg_type = 2;
    config.header.length = sizeof(MSG_CONFIGURATION);

    TCHU_MESSAGE tchu_msg = {0};

    // why does the memcpy not work?  How can I get it to work?
    memcpy(tchu_msg.data, &config+sizeof(MSG_HEADER), sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));

    printf("sizeof(MSG_HEADER) = %u\n", sizeof(MSG_HEADER));
    printf("sizeof(MSG_CONFIGURATION) = %u\n", sizeof(MSG_CONFIGURATION));

    // get garbage in copyconfig
    MSG_CONFIGURATION copyconfig;
    memcpy(&copyconfig+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));

    if(copyconfig.header.start_char != config.header.start_char)
    {
        // we get to here
        printf("mismatch between original and copy\n");
    }
}

int main() {

    TestCopy();

    // I also get Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.
    // when program ends
}

My compiler instantly told me what was wrong:我的编译器立即告诉我出了什么问题:

warning: '__builtin___memcpy_chk' will always overflow destination buffer [-Wbuiltin-memcpy-chk-size]
    memcpy(&copyconfig+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));

Why is that?这是为什么? Well, let's look at the destination:好吧,让我们看看目的地:

&copyconfig + sizeof(MSG_HEADER)

That means "Take the address of copyconfig , treat it as an array, and take the Nth object where N is sizeof(MSG_HEADER) . I think you thought it would add N bytes, but it actually adds N instances of MSG_CONFIGURATION . Instead, use this:这意味着“取copyconfig的地址,将其视为一个数组,并取第 N 个对象,其中 N 为sizeof(MSG_HEADER) 。我认为您认为它会添加 N 个字节,但它实际上添加了 N 个MSG_CONFIGURATION实例。相反,使用这个:

&copyconfig.header + 1

That is, "Take the address of copyconfig.header and go to just beyond it."也就是说,“获取copyconfig.header的地址并转到它之外。”

You could equally do this:你同样可以这样做:

(char*)&copyconfig + sizeof(MSG_HEADER)

Because the size of one char is one byte.因为一个char的大小是一个字节。 Or, since your struct is packed:或者,由于您的结构已打包:

&copyconfig.clear_type

Because that's the address of the first byte you actually want to copy into.因为那是您实际要复制到的第一个字节的地址。

For more details, read: Pointer Arithmetic .有关更多详细信息,请阅读: 指针算术

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM