【问题标题】:Copy struct to buffer将结构复制到缓冲区
【发布时间】:2011-04-08 00:28:22
【问题描述】:

我有一个结构:

struct data{
 int num1;
 int num2;
 int num3;
 int num4;
}

现在,我可以转换单个元素,然后将它们放入缓冲区,但我想将整个结构复制到缓冲区中(char buffer[sizeof(data)])。

有没有办法复制?

【问题讨论】:

  • 鉴于大多数 C 编译器上的 sizof(int) == 4,您将很难将该结构放入 8 字节缓冲区!
  • 怎么样:char buffer[sizeof(struct data)];
  • 右大括号后需要一个分号。此外,您定义的只是一个类型,而不是该类型的值。 sizeof(data) 无效,除非你定义了一个名为 data 的变量,或者有一个 typedef struct data data

标签: c


【解决方案1】:

memcpy可以这样做

Microsoft 系统可以使用memcpy_s 自动检查尺寸

您还需要注意struct data 中的指针。

struct data { 
    int num1;
    char* name;
}

char* name 指向的内存内容不会被 memcpy 复制。您将需要某种更复杂的序列化。

这是一些有效的代码。它复制数据,然后显示结果

struct data{
  int num1;
  int num2;
  int num3;
};

int main(int argc, char** argv)
{
   data my_data;
   my_data.num1 = 64;
   my_data.num2 = 65;
   my_data.num3 = 66;

   char buffer[20];
   memcpy(buffer, &my_data, sizeof(data));

   data copy_data;
   memcpy(&copy_data, buffer, sizeof(data));

   printf("the numbers : %d - %d - %d \n", copy_data.num1, copy_data.num2, copy_data.mum3);



   return 0;
}

【讨论】:

  • 在这种情况下,因为他的目标缓冲区可能小于结构的大小,memcpy(buffer, var_data, sizeof(buffer)) 可能是一个更好的主意。
  • @ughoavgfhw data 是结构的名称,而不是变量的名称,因此您不需要&data
  • 所以,memcpy(buffer, &data, sizeof(data));不起作用。缓冲区中没有任何内容。
  • @Ben 如果 OP 的目标缓冲区小于复制到其中的缓冲区,那将是一个严重的错误,实际上已对问题进行了编辑以解决该问题。
  • @Punit 缓冲区是目标 -- memcpy(buffer &data, sizeof(data)) 当然确实工作如果你定义了struct data data = { ... }。无论如何,给出的答案是错误的,需要编辑。
【解决方案2】:

在您对this answer的评论中,

我正在尝试将此结构复制到闪存 [内存芯片]。 Flash 读/写 API 传递一个字符串。 – Punit 2 小时前

你透露你有一个XY Problem - 你问的是如何实现你的解决方案,而不是如何解决你的问题。您并不是真的想将结构复制到缓冲区,而是想使用需要 char * 参数的 API 将结构中的数据写入 Flash。

其他人指出memcpy 会做你想做的事。但它们都涉及在 RAM 中为这个缓冲区分配内存。使用这些方法会奏效,但会浪费时间和内存。假设您的 Flash API 具有以下功能:

int WriteBlock(int address, char *data, int length);

并且您已将结构存储在名为 data_var 的变量中,您可以以与 memcpy 相同的方式使用您的 API:

int success = WriteBlock(my_address, (char *) &data_var, sizeof(struct data)

为了更清楚并避免强制转换,您可能希望将其包装在一个联合中:

union {
    struct data{
        int num1;
        int num2;
        int num3;
        int num4;
    };
    char data_arr[sizeof(struct data)];
};

这将允许您使用更传统的语法来调用它。

请注意,如果您的结构不连续,这两种方法(和 memcpy!)都可能会失败。例如,也许您的结构如下所示:

struct data{
 int   num1;
 char  num2;
 long  num3;
 short num4;
}

如果您使用的不是 8 位系统,那么这种结构很可能(取决于您的架构)包含间隙。 例如,假设 num1 是 0x12345678,num2 是 0x9A,num3 是 0xBCDEF0123456789A,num4 是 0xBCDE,那么您可能有以下任何一种情况(假设您的内存是零初始化的,并且为清楚起见是 big-endian):

/* 8 位 */ 0x1234 5678 9ABC DEF0 1234 5678 9ABC DE00 /* 16 位 */ 0x1234 5678 009A BCDE F012 3456 789A BCDE /* 32 位 */ 0x1234 5678 0000 0000 0000 009A BCDE F012 3456 789A 0000 0000 0000 BCDE

在这种情况下,您将不得不使用更丑陋的东西,例如以下函数:

int fillDataBuffer(struct data d, char *buffer, int len) 
{
  int i, j = 0;

  for (i = sizeof(d.num1) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num1 >> i); 
  }
  for (i = sizeof(d.num2) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num2 >> i); 
  }
  for (i = sizeof(d.num3) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num3 >> i); 
  }
  for (i = sizeof(d.num4) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num4 >> i); 
  }

  if (j >= len) {
    /* Error!  The buffer wasn't big enough. */
    return 0;
  } else {
    return 1;
  }
}

#pragma pack() 宏,但这可能会使使用该结构的计算变慢,并且您可能宁愿在要进行缓冲时打包它。

【讨论】:

  • 感谢问题的名称!我一直在 SO 和其他地方看到这一点......因此我在回答中说我质疑 OP 真正想要做什么,这导致了你对实际要求的回答。 :-)
  • 能否提一下,对于从 flash api 直接读取地址范围,地址范围必须锁定在内存中,或者地址范围不可分页。
【解决方案3】:

首先,您需要在右大括号后加一个分号。其次,您应该使用 typedef。第三,您应该大写用户类型(有些人建议在您的类型之后加上 _t,但这实际上违反了 C 标准,因为这样的名称是保留的)。第四,您需要复制该类型的值。考虑到所有这些:

typedef struct{
 int num1;
 int num2;
 int num3;
 int num4;
} Data;

Data foo = { 1, 2, 3, 4};
char buffer[sizeof foo]; // at least

memcpy(buffer, &foo, sizeof foo);

但是,我会质疑为什么您实际上要将结构复制到 char 缓冲区。你应该说明你真正想要达到的目标,因为很有可能有更好的方法来实现它。

【讨论】:

  • 我正在尝试将此结构复制到闪存中。 Flash 读/写 API 传递一个字符串。
  • @Punit - 那么你解决了错误的问题!您真的不想复制到 RAM 缓冲区然后复制到 Flash,您希望能够通过字符串 API 传递结构中的数据。我在回答中发布了一些选项。
【解决方案4】:

使用 memcpy 可以将整个结构复制到缓冲区中。 例如,'ob1' 的内容在以下代码中被复制到 'buffer' 中:

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

    struct data{
        int num1;
        int num2;
        int num3;
        int num4;
    };
    int main()
    {
        struct data ob1;
        struct data *buffer = (struct data *)malloc(sizeof(struct data));
        if(buffer == NULL)
            {
               printf("Memory allocation failed\n");
               return;
            }

        ob1.num1 = 1;
        ob1.num2 = 2;
        ob1.num3 = 3;
        ob1.num4 = 4;

        memcpy(buffer, &ob1, sizeof(struct data));

    }

【讨论】:

  • 我了解它是如何工作的,但如果结构数据中有 char* 名称组件。我们该如何处理?复制到缓冲区,然后能够将信息从缓冲区提取回结构。?我创建的缓冲区是 char* 缓冲区,而不是 struct 类型的缓冲区。谢谢
【解决方案5】:

上面的答案只有在结构元素的大小都相同的情况下才有效(假设使用 32 位 cpu 和编译器)。因此,int 将是 32 位,但如果您的结构包含例如 char 以及 int,则编译器可能会将 char 填充为 32 位以进行数据对齐。

您可以在结构的每个元素上尝试 sprintf,并在将每个元素加载到 char 缓冲区时将每个元素转换为正确的大小。

或者,您可以使用在每次写入缓冲区时按每个元素的正确字节数递增索引的大小来逐个加载缓冲区元素。冗长但可以说效率更高的 id 资源稀缺,数据量很大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多