2011-02-15 190 views
0

我有一個工會如下:聯盟爲unsigned long long int類型投

typedef unsigned long GT_U32; 
typedef unsigned short GT_U16; 
typedef unsigned char GT_U8; 

typedef union 
{ 
    GT_U8 c[8]; 
    GT_U16 s[4]; 
    GT_U32 l[2]; 
} GT_U64; 

我想這個聯盟投在以下幾點:

typedef unsigned long long int UINT64; 

我寫的轉換函數如下:

UINT64 gtu64_to_uint64_cast(GT_U64 number_u) 
{ 
    UINT64 casted_number = 0; 

    casted_number = number_u.l[0]; 
    casted_number = casted_number << 32; 
    casted_number = casted_number | number_u.l[1]; 

    return casted_number; 
} 

此功能使用l構件進行變速和按位或。如果工會的sc成員用於設置其值,會發生什麼情況?

我不確定這個函數是否總能正確地轉換值。我懷疑它與longshort的字節順序有關。任何身體可以幫助嗎?

下面列出了完整的示例程序。

#include <stdio.h> 

typedef unsigned long GT_U32; 
typedef unsigned short GT_U16; 
typedef unsigned char GT_U8; 

typedef union 
{ 
    GT_U8 c[8]; 
    GT_U16 s[4]; 
    GT_U32 l[2]; 
} GT_U64; 

typedef unsigned long long int UINT64; 

UINT64 gtu64_to_uint64_cast(GT_U64 number_u) 
{ 
    UINT64 casted_number = 0; 

    casted_number = number_u.l[0]; 
    casted_number = casted_number << 32; 
    casted_number = casted_number | number_u.l[1]; 

    return casted_number; 
} 

int main() 
{ 
    UINT64 left; 
    GT_U64 right; 

    right.s[0] = 0x00; 
    right.s[1] = 0x00; 
    right.s[2] = 0x00; 
    right.s[3] = 0x01; 
    left = gtu64_to_uint64_cast(right); 

    printf ("%llu\n", left); 
    return 0; 
} 
+0

這一個如果訪問你的數組的mem areya ..「right.l [3] = 0x01;」 – eaanon01 2011-02-15 13:44:43

+1

代碼錯了,沒有l [3]。應該是,我想。 – Serkan 2011-02-15 13:48:22

+0

糾正了這一點。 – 2011-02-15 13:48:22

回答

1

這真是醜陋和依賴於實現 - 只是使用memcpy,例如,

UINT64 gtu64_to_uint64_cast(GT_U64 number_u) 
{ 
    UINT64 casted_number; 

    assert(sizeof(casted_number) == sizeof(number_u)); 

    memcpy(&casted_number, &number_u, sizeof(number_u)); 

    return casted_number; 
} 
+0

memcpy()同樣醜陋且依賴於實現。結構/聯合可以在其內部的任何位置填充字節。我沒有看到assert()對於填充是比assert()更好還是更差。 – Lundin 2011-02-15 13:54:42

+0

@Lundin:如果聯盟存在任何填充/對齊問題,那麼所有投注都無效 - 將聯合投射到64位int永遠不會完全可靠。使用上述解決方案的好處是,它至少不會遭受排序問題,並且有些面向未來。你能提出更好的解決方案嗎? – 2011-02-15 13:58:26

0

大概要投一個更簡單的方法是使用工會用長長的成員:

typedef unsigned long long int UINT64; 
typedef unsigned long GT_U32; 
typedef unsigned short GT_U16; 
typedef unsigned char GT_U8; 

typedef union 
{ 
    GT_U8 c[8]; 
    GT_U16 s[4]; 
    GT_U32 l[2]; 
    UINT64 ll; 
} GT_U64; 

然後,只需訪問ll將獲得64位的值,而不必做一個明確的轉換。您需要告訴編譯器使用單字節struct打包。

0

您不指定「正確投射值」的含義。

此代碼將以最簡單的方式投射,但根據您的系統字典順序,它會給出不同的結果。

所有的
UINT64 gtu64_to_uint64_cast(GT_U64 number_u) { 
    assert(sizeof(UINT64) == sizeof(GT_U64)); 
    return *(UINT64 *) &number_u; 
} 
1

首先,請使用從 「stdint.h的」 typedef S代表這樣一個目的。你有很多關於整數類型寬度的假設,不要那樣做。

如果S或C成員工會 用於設置其 值會發生什麼?

如果存在填充字節或填充位,讀取通過另一個成員寫入的聯合的成員可能會導致未定義的行爲。唯一的例外是unsigned char,它可能總是用於訪問單個字節。所以通過c訪問很好。通過s訪問可能會(在極不可能的情況下)導致未定義的行爲。

在你的情況下,沒有像「正確」投射那樣的東西。這取決於你想如何將一個小數字數組解釋爲一個大數字。對於這個任務的一種可能的解釋是你給的那個。

1

這段代碼應該獨立工作,不需要填充,字節順序,聯合訪問和隱式整數提升。

uint64_t gtu64_to_uint64_cast (const GT_U64* number_u) 
{ 
    uint64_t casted_number = 0; 
    uint8_t i; 


    for(i=0; i<8; i++) 
    { 
     casted_number |= (uint64_t) number_u->c[i] << i*8U; 
    } 

    return casted_number; 
} 
1

如果你無法改變工會的聲明,包括一個明確的64位字段,也許你可以把它包裝?就像這樣:

UINT64 convert(const GT_U64 *value) 
{ 
    union { 
    GT_U64 in; 
    UINT64 out; 
    } tmp; 

    tmp.in = *value; 
    return tmp.out; 
} 

確實違反,說你只能從最後寫入工會會員閱讀,所以也許它會設置你的頭髮着火的規則。我認爲這將是相當安全的,雖然沒有看到像這樣的工會會包括填充的情況,但我當然可能是錯的。

我主要想包括這一點,因爲你不能改變「輸入」聯合聲明並不意味着你不能通過包裝它來做幾乎相同的事情。