結構體copy問題
c語言中,結構使用是非常頻繁的,操作結構體時,我們一般使用memcpy對結構體進行copy賦值,其實我們忽略了一點,同一種類型結構體是可以直接進行賦值的。另外,本文介紹下使用memcpy copy結構體時的一些注意事項。
一.結構體內存對齊
使用memcpy對結構體進行內存copy,首先要知道結構體的大小計算,最簡單的方法使用sizeof(結構體類型)進行計算。當然,本文也介紹下結構體所佔空間大小計算方法。
主要有兩原則:
1.對結構體成員進行存儲時,要以自身爲起始地址(相對地址),每個成員存放到地址要是自身大小的整數倍。
例如:(4+4+8)
#include<stdio.h>
typedef struct test
{
char a;
int b;
double c;
}test_t;
int main(int argc, const char *argv[])
{
test_t a;
printf("sizeof:%d\n",(int)sizeof(test_t));
return 0;
}
2.計算出來的結構體總大小要爲其成員最大寬度的整數倍
例如:(8+8+8)
#include<stdio.h>
typedef struct test
{
char a;
double c;
int b;
}test_t;
int main(int argc, const char *argv[])
{
test_t a;
printf("sizeof:%d\n",(int)sizeof(test_t));
return 0;
}
二.結構體copy
使用memcpy對結構體進行內存拷貝,歸根到底就是將內存的數據從一個地址複製到另一個地址上。
先貼上測試代碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//無指針結構體
typedef struct test
{
char str[16]; //name
char s; //sex
int m; //age
}test_t;
//有指針結構體
typedef struct tests
{
test_t * atest;
char job[20];
}tests_t;
//結構體成員定義存在差異
typedef struct testn
{
char str[20]; //name
char s; //sex
int m; //age
}testn_t;
int main(int argc, const char *argv[])
{
//測試1
test_t nab1,nab2,nab3;
strcpy(nab1.str,"tom");
nab1.s = 'm';
nab1.m = 20;
memcpy(&nab2,&nab1,sizeof(test_t));
nab3 = nab1;
printf("nab1.name:%s,nab1.sex:%c,nab1.age:%d\n",nab1.str,nab1.s,nab1.m);
printf("nab2.name:%s,nab2.sex:%c,nab2.age:%d\n",nab2.str,nab2.s,nab2.m);
printf("nab3.name:%s,nab3.sex:%c,nab3.age:%d\n",nab3.str,nab3.s,nab3.m);
//測試二
tests_t nabs1,nabs2,nabs3;
nabs1.atest = &nab1;
strcpy(nabs1.job,"teacher");
memcpy(&nabs2,&nabs1,sizeof(tests_t));
nabs3 = nabs1;
printf("%s,%c,%d,%s\n",nabs1.atest->str,nabs1.atest->s,nabs1.atest->m,nabs1.job);
printf("%s,%c,%d,%s\n",nabs2.atest->str,nabs2.atest->s,nabs2.atest->m,nabs2.job);
printf("%s,%c,%d,%s\n",nabs3.atest->str,nabs3.atest->s,nabs3.atest->m,nabs3.job);
//測試三
printf("test_t:%d,testn_t:%d\n",(int)sizeof(test_t),(int)sizeof(testn_t));
testn_t nabn;
nabn.m=8;
memcpy(&nabn,&nab1,sizeof(test_t));
printf("nab1.name:%s,nab1.sex:%c,nab1.age:%d\n",nabn.str,nabn.s,nabn.m);
printf("nab1.name:%s,nab1.sex:%d,nab1.age:%d\n",nabn.str,nabn.s,nabn.m);
return 0;
}
編譯運行:
測試一:
對於同一種類型的結構體,內存拷貝與結構體直接賦值是等價的,至少在本例中等價。
測試二:
如果結構體中存在指針變量,其大小就是四個字節,並不影響結構體直接賦值或者使用memcpy。
測試三:
對於不同類型的結構體進行拷貝,會出現什麼問題。
現在有test_t,testn_t兩種類型的結構體,從log看test_t 佔24個字節,testn_t佔28個字節大小,實際計算也是如此。現在將test_t類型的結構體copy到testn_t類型的結構體,會出現什麼結果。
由上圖可以看出,直接內存拷貝。
由測試三最後一條log,可以看出,與上圖是對應的,至於字符串打印沒變,是因爲%s打印遇到’\0’結束,我們也可以做個測試。
#include<stdio.h>
int main(int argc, const char *argv[])
{
char str[20] ="12345678a\0 555";
char string[20] = "123456789a 555";
printf("str:%s\nstring:%s\n",str,string);
return 0;
}
編譯運行