簡體   English   中英

聯合到unsigned long long int演員表

[英]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成員執行移位和按位或。 如果使用聯合的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;
}

這確實很丑陋,並且依賴於實現-只需使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM