在C语言中将结构体复制到另一个结构体

87

我想将一个相同的结构体复制到另一个结构体中,并在以后将其用作与第一个结构体进行比较的依据。问题是当我这样做时,我的编译器会给出警告!我应该用另一种方式来处理它吗,还是我做错了?

在头文件中:

extern struct RTCclk
{
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t mday;
uint8_t month;
uint8_t year;
}
RTCclk;
在C文件中:
struct RTCclk RTCclk;
struct RTCclk RTCclkBuffert;

void FunctionDO(void)
{
   ... // Some Code
   /* Copy first struct values into the second one */
   memcpy(&RTCclk, &RTCclkBuffert, sizeof RTCclk);
}

6
编译器会发出什么警告? - Nick Shaw
1
PS - sizeof调用应该是sizeof(RTCclk),而不是sizeof TRCclk吧? - Nick Shaw
只是一个警告[2054],指针转换可疑,我应该使用memset或memmove吗? - Christian
7
@NickShaw:括号是多余的,例如 i = (2)+(4);。我不喜欢它们,但有些人喜欢。 - pmg
1
我能找到的唯一关于“警告[2054]可疑指针转换”的参考与Microchip编译器有关,适用于PIC。它们的内存映射可以通过不同的方式访问,并且可能会受到像银行业务之类的影响,因此您应该仔细检查memcpy()的签名以及链接器放置变量的位置。也许像已经回答的那样使用结构分配是最安全的选择。 - tinman
显示剩余2条评论
7个回答

191

对于简单的结构体,你可以使用像你现在这样的memcpy,或者直接将一个结构体赋值给另一个:

RTCclk = RTCclkBuffert;
编译器会为您创建复制该结构的代码。
关于复制的重要说明:这是一种浅复制,就像使用memcpy一样。这意味着,如果您有一个包含指针的结构体,那么只有实际指针会被复制,而不是它们指向的内容。因此,在复制之后,您将拥有两个指向相同内存的指针。

8
即使在结构体中有数组,它也能正常工作吗?例如: struct example{ int myThings[10000]; char name[100]; int id; }; - M4rk
1
我该如何进行深度复制呢? - User
5
如果一个结构体不包含指针,而且所包含的结构体也没有指针等等,那么就没问题了。如果有任何指针存在,你需要分配新的内存,并使用例如 memcpy 进行复制。 - Some programmer dude
是的,这是一个链表。所以只需复制链表中的第一项即可? - User
4
如果您想复制一个列表,最简单的方法是从头开始创建一个新列表。遍历现有列表并获取其数据,然后将其添加到新列表中即可。 - Some programmer dude

19

那么我应该这样做:dowhile ( RTCclk.second != RTCclkBuffert.second || RTCclk.minute != RTCclkBuffert.minute || RTCclk.hour != RTCclkBuffert.hour || RTCclk.mday != RTCclkBuffert.mday ); - Christian
1
是的。虽然将比较封装在一个函数中可能会更整洁。 - Graham Borland

7

在C语言中复制结构体,只需要按照以下方式分配值:

struct RTCclk RTCclk1;
struct RTCclk RTCclkBuffert;

RTCclk1.second=3;
RTCclk1.minute=4;
RTCclk1.hour=5;

RTCclkBuffert=RTCclk1;

现在RTCclkBuffert.hour的值为5,
RTCclkBuffert.minute的值为4,
RTCclkBuffert.second的值为3。

2
此外,一个很好的例子是......
struct point{int x,y;};
typedef struct point point_t;
typedef struct
{
    struct point ne,se,sw,nw;
}rect_t;
rect_t temp;


int main()
{
//rotate
    RotateRect(&temp);
    return 0;
}

void RotateRect(rect_t *givenRect)
{
    point_t temp_point;
    /*Copy struct data from struct to struct within a struct*/
    temp_point = givenRect->sw;
    givenRect->sw = givenRect->se;
    givenRect->se = givenRect->ne;
    givenRect->ne = givenRect->nw;
    givenRect->nw = temp_point;
}

2

memcpy函数要求前两个参数是void*类型。

尝试使用以下代码:

memcpy((void*)&RTCclk, (void*)&RTCclkBuffert, sizeof(RTCclk));

顺便说一句,虽然没有必要,但按照惯例,sizeof运算符需要括号。在C语言中有很多可以让代码难以维护的写法,遵循惯例是一个好的(可雇用的)C程序员的标志。


据我理解,鼓励不使用 sizeof 运算符的括号。 - Kami Kaze

1
你的 memcpy 代码是正确的。
我猜你可能缺少了 string.h 的引用。所以编译器会假设 memcpy 的原型错误,从而产生警告。
不管怎样,为了简单起见,你应该只是分配结构体(正如 Joachim Pileborg 指出的那样)。

3
memcpy 用于结构体时表示:“我不知道我使用的语言是否支持结构体赋值”。唯一需要在两个完全相同类型的结构体之间使用 memcpy 的原因是,出于某种原因,您需要确保结构体填充被完全保留。 - Kaz

0
我认为你应该将指针转换为(void *)以消除警告。
memcpy((void *)&RTCclk, (void *)&RTCclkBuffert, sizeof RTCclk);

另外,您使用了没有括号的sizeof,您可以将其与变量一起使用,但如果RTCclk被定义为数组,则sizeof将返回整个数组的大小。如果您使用类型使用sizeof,则应该使用括号。

sizeof(struct RTCclk)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接