【问题标题】:Why does this memory copy of a struct not copy bytes to byte stream as expected?为什么这个结构的内存副本没有按预期将字节复制到字节流?
【发布时间】:2016-04-27 11:36:02
【问题描述】:

我需要序列化一个结构,并且我正在尝试使用 memcpy 来执行此操作。但它不起作用。我可以通过查看字节流来判断——我看到了垃圾字符。为什么?

还有运行时错误:

运行时检查失败 #2 - 变量“地址”周围的堆栈已损坏。

发生了什么,我该如何解决?

我正在使用#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
}

【问题讨论】:

  • 欢迎来到 Stack Overflow!听起来您可能需要学习如何使用调试器来逐步执行代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。进一步阅读:How to debug small programs.
  • 偏移到这样的结构中是否明智?成员的顺序是否由 C 保证?为简单起见,您能否不从 MSG_CONFIGURATION 中删除 MSG_HEADER 并将它们单独发送,并避免偏移到这样的结构中。
  • 你知道&amp;config+sizeof(MSG_HEADER) 是做什么的吗?它将地址&amp;config 前进sizeof(MSG_HEADER)*sizeof(MSG_CONFIGURATION) 字节。我不认为那是你想要的。
  • 你不连载,而只是重新诠释。对 bitops&shifts 使用正确的序列化。并且 C 标准没有定义该 pragma(或大多数其他)的行为

标签: c pointers memory


【解决方案1】:

我的编译器立即告诉我出了什么问题:

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));

这是为什么呢?好吧,我们来看看目的地:

&copyconfig + sizeof(MSG_HEADER)

意思是“取copyconfig的地址,把它当作一个数组,取N为sizeof(MSG_HEADER)的第N个对象。我想你以为它会增加N个字节,但它实际上增加了N个@的实例987654326@。改为使用:

&copyconfig.header + 1

也就是说,“取copyconfig.header 的地址,然后到它后面。”

你同样可以这样做:

(char*)&copyconfig + sizeof(MSG_HEADER)

因为一个char 的大小是一个字节。或者,由于您的结构已打包:

&copyconfig.clear_type

因为这是您实际要复制到的第一个字节的地址。

更多详情,请阅读:Pointer Arithmetic

【讨论】:

  • 逻辑上应该是&amp;copyconfig.clear_type,不管包装如何
  • win 的编译器警告。
  • 啊,是的,因为 + 3 是超过 3 个 MSG_CONFIGURATION 的增量。迭代数组时这是有道理的 - 但在我的情况下不是。是的,下次我会检查地址。
  • 引用:but it actually adds N instances of MSG_HEADER - 为什么?代码上写着MSG_CONFIGURATION copyconfig;,所以它不是 MSG_CONFIGURATION 的 N 个实例吗?
  • @4386427:你说得对,我现在已经解决了。感谢您指出错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多