[英]Union to unsigned long long int cast
我有一個工會,如下所示:
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
成員執行移位和按位或。 如果使用聯合的s
或c
成員來設置其值,將會怎樣?
我不確定此函數是否總是會正確地轉換值。 我懷疑這與long
和short
的字節順序有關。 有身體可以幫助嗎?
下面列出了完整的示例程序。
#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;
}
這確實很丑陋,並且依賴於實現-只需使用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;
}
為此,請首先使用“ stdint.h”中的typedef
。 對於整數類型的寬度,您有很多假設,請不要這樣做。
如果使用聯合的s或c成員來設置其值,將會怎樣?
如果存在填充字節或填充位,則讀取通過另一個成員寫入的並集的成員可能會導致未定義的行為。 唯一的例外是可以始終用於訪問各個字節的unsigned char
。 因此,通過c
訪問是可以的。 通過s
訪問可能(在極不可能的情況下)導致未定義的行為。
在您的情況下,沒有像“正確”的強制轉換這樣的事情。 它僅取決於您要將小數數組解釋為一個大數的方式。 您可以為該任務提供一種可能的解釋。
該代碼應獨立於填充,字節序,聯合訪問和隱式整數提升而工作。
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;
}
如果您不能將並集的聲明更改為包含顯式的64位字段,也許可以包裝它? 像這樣:
UINT64 convert(const GT_U64 *value)
{
union {
GT_U64 in;
UINT64 out;
} tmp;
tmp.in = *value;
return tmp.out;
}
這確實違反了規定,即您只能從上次寫入的工會成員中讀取內容,因此可能會使您着火。 我認為這將是相當安全的,看不到像這樣的聯合會包含填充的情況,但是我當然可能是錯的。
我主要想包含此內容,因為僅僅因為您不能更改“ input”聯合的聲明並不意味着您不能通過包裝它來做幾乎相同的事情。
可能更簡單的轉換方法是對長成員使用union:
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
打包。
您沒有指定“正確地傳遞值”的含義。
這段代碼將以最簡單的方式進行轉換,但是根據您的系統字節順序,它將給出不同的結果。
UINT64 gtu64_to_uint64_cast(GT_U64 number_u) {
assert(sizeof(UINT64) == sizeof(GT_U64));
return *(UINT64 *) &number_u;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.