2011-03-23 66 views
2

我有兩個對象都同一類型的,例如:如何使用memcpy交換兩個對象的部分?

typedef struct s_Object 
{ 
    signed int a[3]; 
    double float b; 
    unsigned short int c[30]; 
    struct s_Object *next, 
        *prev; 
} t_Object; 
t_Object A, B; 

我需要一個像一些通用的功能:

swap_vars(&A, &B); 

不會掉球,但所有其他數據的對象可以包含。在C中可能嗎?

假設指針放置在最高地址,我的第一個想法是:

void swap_vars(t_Object *pA, t_Object *pB){ 
    t_Object C; 
    memcpy(&C, pA, sizeof(t_Object)-sizeof(t_Object *)*2; 
    memcpy(pA, pB, sizeof(t_Object)-sizeof(t_Object *)*2; 
    memcpy(pB, &C, sizeof(t_Object)-sizeof(t_Object *)*2; 
} 

,但我不知道是怎麼便攜式它(或者錯誤的話)?

我正在尋找最便攜的解決方案。

+1

你不應該假設任何關於結構的佈局,只是使用他們的名字memcopy個別成員 – 2011-03-23 13:46:38

+0

@Martin:這不是一個漂亮的解決方案,因爲每次我將改變對象的類型描述,我必須更新這個函數以及。 – psihodelia 2011-03-23 13:50:51

回答

3

使用offsetof

memcpy(&C, pA, offsetof(t_Object, next)); 

的原因是t_Object可能在年底有填充,因此,如果您複製所有,但最後8個字節,你可能會複製部分或全部指針。

我不確定這是否嚴格符合 - 標準說你可以複製整個對象,但我不確定它對部分對象的說法。

這會有點奇怪,但想象一下,這個結構在中間有一些填充,有些在最後,實現用隨機選擇的相同字節值填充每個對象中的所有填充,然後稍後檢查以查看填充是否一致。我不認爲認爲這是禁止的。那麼這是行不通的。

實際上,這是非常便攜的。特別是,成員必須按照他們定義的順序出現,所以offsetof(t_Object, next)肯定會捕獲對象的部分(但不包括)指針。

如果你能夠改變結構,那麼你可以從一個交換部分建立起來,並且unswapped部分:

typedef struct payload { 
    signed int a[3]; 
    double float b; 
    unsigned short int c[30]; 
} payload; 

typedef struct s_Object { 
    payload data; 
    struct s_Object *next, *prev; 
} t_Object; 

交換則是:

payload C = pA->data; 
pA->data = pB->data; 
pB->data = C; 

編輯:提示memcpy vs assignment in C -- should be memmove?

這後者也有一個好處,就是它在標準工作時保證工作時pA == pB。與memcpy不一樣,因爲第二個副本的區域重疊。對於自交換來說,這兩者都不是最佳選擇,但一般來說,這些可能非常罕見,如果不需要,不值得檢查指針。

+0

謝謝,使用有效載荷的好主意!看起來我已經在某處看到過類似的東西(無論是git還是python源代碼)。 – psihodelia 2011-03-23 14:06:02