memcpy 缓冲区中的复杂结构

发布于 2025-01-14 03:31:21 字数 439 浏览 6 评论 0原文

我在 C 方面相对较新,并且在缓冲区中 memcpy 结构时遇到一些问题;

我有这个结构:

`typedef struct {
        uint8_t size_of_payload;
        uint8_t command;
        unsigned char* payload;

}__attribute__((packed)) mystruct``

我想在 tx_buffer[SIZE] 中复制该结构的值,包括有效负载指向的值。 Payload 指向一个 char 数组,其大小等于 size_of_payload 。

memcpy(&tx_buffer,&mystruct,sizeof(mystruct));

仅复制有效负载地址的值。

有可能这样做吗?

i'm relatively newer in C and i have some problems to memcpy a struct in a buffer;

I have this struct:

`typedef struct {
        uint8_t size_of_payload;
        uint8_t command;
        unsigned char* payload;

}__attribute__((packed)) mystruct``

and i want to copy in a tx_buffer[SIZE] the values of this struct, including the value pointed by payload.
payload point to an array of char with a size equals to the size_of_payload .

memcpy(&tx_buffer,&mystruct,sizeof(mystruct));

copies only the value of payload address.

It is possible do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浮华 2025-01-21 03:31:21

嗯,不可能通过一次简单的调用来完成这一任务。您必须“手动”执行此操作。
memcpy 只能将一个内存区域复制到另一内存区域。您的源内存区域的结构与您希望的目标内存区域的结构不同,因此必须手动完成。
让我们首先复制前两个字段

memcpy(&tx_buffer+0*sizeof(uint8_t),&mystruct.size_of_payload, 1*sizeof(uint8_t));
memcpy(&tx_buffer+1*sizeof(uint8_t),&mystruct.command, 1*sizeof(uint8_t));

我们在这里所做的是将第一个元素复制到 tx_buffer 的位置 0,然后将第二个元素复制到之后的 1 个字节的位置。
对于字符串,我们不知道长度。我们可以找到它并执行 memcpy,但还有一个方便的替代方案:

strcpy(&tx_buffer+2*sizeof(uint8_t), mystruct.payload)

Well it isn't possible to do it in one simple call. You will have to do it 'manually'.
memcpy can only copy one memory region to an other. Your source memory region isn't structured the way you want it at the destination, so will have to do it manually.
Let's first copy the first two fields

memcpy(&tx_buffer+0*sizeof(uint8_t),&mystruct.size_of_payload, 1*sizeof(uint8_t));
memcpy(&tx_buffer+1*sizeof(uint8_t),&mystruct.command, 1*sizeof(uint8_t));

What we do here, is copy the first element to position zero of tx_buffer, and the second to position 1 byte after that.
For the string we don't know the length. We could find it and do a memcpy, but there is a convenient alternative:

strcpy(&tx_buffer+2*sizeof(uint8_t), mystruct.payload)
拥抱影子 2025-01-21 03:31:21

整个设置对我来说似乎有点奇怪。为什么需要“扁平化”结构?或者如果需要合理,为什么选择这种结构布局?无论如何,将尝试举例说明(我认为的)最简单的方法(从其他标准来看这不是最好的)。

由于该结构包含一个作为指针的成员(一层间接),因此不能一次性完成。
在这种特殊情况下(因为指针是最后一个成员),方法是:

  1. 复制结构体的内容直到指针成员
  2. 复制取消引用的指针成员的内容(基于 size 成员)

请注意,对于更复杂的结构,具有交替的指针和常规成员,您需要对相同类型的第一个st成员进行一次memcpy调用+对每个成员进行一次额外的调用连续的成员类型(正常-> 指针指针-> 正常指针-> 指针)。

code00.c

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

#define BUF_DIM 0xFF  // Make sure it's large enough


typedef struct {
    uint8_t size_of_payload;
    uint8_t command;
    unsigned char *payload;
} __attribute__((packed)) Data;


size_t dataSize(const Data *pData)
{
    if (pData == NULL)
        return 0;
    return offsetof(Data, payload) + pData->size_of_payload;
}

size_t copyData(const Data *pData, uint8_t *pBuf)
{
    size_t sz = dataSize(pData);
    if (sz == 0)
        return 0;
    size_t ofs = offsetof(Data, payload);
    memcpy(pBuf, pData, ofs);
    memcpy(pBuf + ofs, pData->payload, pData->size_of_payload);
    return sz;
}


int main()
{
    unsigned char array[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'c', 'd' };
    Data data = { sizeof(array), 123, array };
    uint8_t buf[BUF_DIM] = { 0 };
    copyData(&data, buf);
    size_t ds = dataSize(&data);
    printf("Size: %ld\nBuf:\n", ds);
    for (size_t i = 0; i < ds; ++i)
        printf("0x%02X(%c) ", buf[i], buf[i]);

    printf("\nDone.\n");
    return 0;
}

输出

(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q071451221]> 〜/ sopr.sh
### 设置较短的提示,以便在粘贴到 StackOverflow(或其他)页面时更好地适应 ###

【064位提示】> LS
main00.c
【064位提示】> gcc -o main00.exe main00.c
【064位提示】> ./main00.exe
尺寸:16
缓冲:
0x0E() 0x7B({) 0x30(0) 0x31(1) 0x32(2) 0x33(3) 0x34(4) 0x35(5) 0x36(6) 0x37(7) 0x38(8) 0x39(9) 0x41(A ) 0x42(B) 0x63(c) 0x64(d)
完毕。

This whole setup seems a bit strange to me. Why the need to "flatten" the structure? Or if the need is justified, why was this structure layout chosen? Anyway, will try to exemplify (what I consider) the easiest way (which from other criteria wouldn't be the best).

Since the structure contains a member which is a pointer (a level of indirection), it can't be done in one go.
In this particular case (as the pointer is the last member), the approach is to:

  1. Copy the contents of the struct till the pointer member
  2. Copy the contents of the dereferenced pointer member (based on the size member)

Note that for more complex structures, with alternating pointer and regular members, you'd need one memcpy call for the 1st member(s) of the same type + one additional call for each consecutive member types (normal -> pointer, pointer -> normal, pointer -> pointer).

code00.c

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

#define BUF_DIM 0xFF  // Make sure it's large enough


typedef struct {
    uint8_t size_of_payload;
    uint8_t command;
    unsigned char *payload;
} __attribute__((packed)) Data;


size_t dataSize(const Data *pData)
{
    if (pData == NULL)
        return 0;
    return offsetof(Data, payload) + pData->size_of_payload;
}

size_t copyData(const Data *pData, uint8_t *pBuf)
{
    size_t sz = dataSize(pData);
    if (sz == 0)
        return 0;
    size_t ofs = offsetof(Data, payload);
    memcpy(pBuf, pData, ofs);
    memcpy(pBuf + ofs, pData->payload, pData->size_of_payload);
    return sz;
}


int main()
{
    unsigned char array[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'c', 'd' };
    Data data = { sizeof(array), 123, array };
    uint8_t buf[BUF_DIM] = { 0 };
    copyData(&data, buf);
    size_t ds = dataSize(&data);
    printf("Size: %ld\nBuf:\n", ds);
    for (size_t i = 0; i < ds; ++i)
        printf("0x%02X(%c) ", buf[i], buf[i]);

    printf("\nDone.\n");
    return 0;
}

Output:

(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q071451221]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[064bit prompt]> ls
main00.c
[064bit prompt]> gcc -o main00.exe main00.c
[064bit prompt]> ./main00.exe
Size: 16
Buf:
0x0E() 0x7B({) 0x30(0) 0x31(1) 0x32(2) 0x33(3) 0x34(4) 0x35(5) 0x36(6) 0x37(7) 0x38(8) 0x39(9) 0x41(A) 0x42(B) 0x63(c) 0x64(d)
Done.
尐籹人 2025-01-21 03:31:21

使用灵活数组成员。您将拥有更简单的代码:

typedef struct {
        uint8_t size_of_payload;
        uint8_t command;
        uint8_t payload[];
} mystruct;

分配结构:

mystruct *allocMyStruct( uint_8 command, uint8_t size, uint8_t *payload )
{
    mystruct *m = malloc( sizeof( *m ) + size );
    m->size_of_payload = size;
    m->command = command;
    memcpy( m->payload, payload, size );

   return( m )
}

复制:

mystruct *m = ...
 .
 .
 .
// copy *ALL* the fields and the payload
memcpy( txBuffer, m, sizeof( *m ) + m->size_of_payload );

释放结构:

mystruct *m = ...
 .
 .
 .
free( m );

灵活数组成员的唯一缺点是您不能将它们分配为局部或静态变量。

您无法做到这一点

mystruct m;

当您使用灵活的数组成员时,

。但与结构中具有几乎必须动态分配的 uint_t *payload 指针相比,实际上并没有失去灵活性。

在这种情况下,没有理由不使用灵活的数组成员。

Use a flexible array member. You'll have much simpler code:

typedef struct {
        uint8_t size_of_payload;
        uint8_t command;
        uint8_t payload[];
} mystruct;

Allocate a structure:

mystruct *allocMyStruct( uint_8 command, uint8_t size, uint8_t *payload )
{
    mystruct *m = malloc( sizeof( *m ) + size );
    m->size_of_payload = size;
    m->command = command;
    memcpy( m->payload, payload, size );

   return( m )
}

Copy:

mystruct *m = ...
 .
 .
 .
// copy *ALL* the fields and the payload
memcpy( txBuffer, m, sizeof( *m ) + m->size_of_payload );

Free a structure:

mystruct *m = ...
 .
 .
 .
free( m );

The only drawback to a flexible array member is you can't allocate them as local or static variables.

You can't do

mystruct m;

when you're using flexible array members.

But compared to having a uint_t *payload pointer in the structure that pretty much has to be allocated dynamically, in reality there's no flexibility lost.

There's no reason not to use a flexible array member in a case like this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文