簡體   English   中英

使用指針將字節數組轉換為unsigned int

[英]Convert byte array to unsigned int using pointers

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;
unsigned int j = *f;
printf("%u\n", j);

因此,如果內存看起來像這樣:0000 0000 0000 0000 0000 0000 0000 0000 0001

程序輸出0。如何使其輸出整個32位的uint值?

因為您正在使用類型提升。 訪問時, char將提升為int 您將無法對此進行診斷。 因此,您正在做的事情是取消引用char數組中的第一個元素(即0),並將其分配給一個int ...,其結果同樣為0。

您想要做的是技術上未定義的行為,但通常可以。 您想這樣做:

unsigned int j = *reinterpret_cast<unsigned int*>(f);

此時,您將要處理未定義的行為和平台的字節序。 您可能沒有想要在字節流中記錄的值。 您正在涉足需要對編譯器和目標體系結構有深入了解的領域。

假設你的平台支持32位長度的整數,你可以做以下的達到你想要的那種演員

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;

uint32_t j;
memcpy(&j,f,sizeof(j));
printf("%u\n", j);

注意整數表示中的字節序。

為了確保您的代碼在小端和大端系統上均可工作,您可以執行以下操作:

char f[4] = {0,0,0,1};
int32_t j = *((int32_t *)f);
j=ntohl(j);
printf("%d", j);

這將在小字節序和大字節序系統上打印1。 如果不使用ntohl,將僅在Big Endian系統上打印1。

該代碼有效,因為為f分配值的方式與在Big Endian系統中相同。 由於網絡順序也是Big Endian,因此ntohl將正確轉換j 如果主機是Big Endian,則j將保持不變。 如果主機是Little Endian,則j的字節將被反轉。

該行發生了什么:

unsigned int j = *f; 

只是將f的第一個元素分配給整數j。 它等效於:

unsigned int j = f[0];

並且由於f [0]為0,所以實際上只是將0賦給整數:

unsigned int j = 0;

您將必須轉換f的元素。

重新解釋將始終導致未定義的行為。 以下示例顯示了這種用法,並且始終錯誤的

unsigned int j = *( unsigned int* )f;

未定義的行為可能會產生任何結果,甚至是正確的結果。 即使您第一次運行該代碼似乎產生正確的結果,也不能證明該程序已定義。 該程序仍未定義,並且可能隨時產生不正確的結果。

沒有技術上未定義的行為或通常無法運行的程序,該程序是未定義的還是未定義的。 依靠這種說法是危險和不負責任的。

幸運的是,我們不必依賴這樣的錯誤代碼。

您需要做的就是選擇要存儲在f中的整數的表示形式,然后將其轉換。 看來您要存儲在big-endian中,每個元素最多8位。 這並不意味着機器必須是高位優先的,而只是要在f中編碼的整數的表示形式。 在機器上表示整數並不重要,因為此方法是完全可移植的。

這意味着最高有效字節將首先出現。 最高有效字節為f [0],最低有效字節為f [3]。

我們將需要一個能夠存儲至少32位的整數,並鍵入unsigned long來做到這一點。

char類型用於存儲字符而不是整數。 應該使用無符號整數類型,例如unsigned char。

然后,僅必須進行以f編碼的big-endian的轉換:

unsigned char encoded[4] = { 0 , 0 , 0 , 1 };
unsigned long value = 0;
value = value | ( ( ( unsigned long )encoded[0] & 0xFF ) << 24 );
value = value | ( ( ( unsigned long )encoded[1] & 0xFF ) << 16 );
value = value | ( ( ( unsigned long )encoded[2] & 0xFF ) << 8 );
value = value | ( ( ( unsigned long )encoded[3] & 0xFF ) << 0 );

關於發布的代碼:

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;
unsigned int j = *f;
printf("%u\n", j);
  1. 在C語言中, malloc()的返回類型為void* ,可以將其分配給任何其他指針,因此強制轉換只會使代碼混亂,並且在對代碼進行維護時可能會出現問題。
  2. C標准將sizeof(char)定義為1,因此作為傳遞給malloc()的表達式的一部分,表達式絕對無效
  3. 一個int的大小不一定為4(以微處理器或64位體系結構為例)
  4. 函數: calloc()將所有字節預先設置為0x00
  5. 哪個字節應設置為0x01取決於基礎架構的Endianness

現在讓我們假設您的計算機是little Endian架構。 (即Intel或類似產品)

那么代碼應類似於以下內容:

#include <stdio.h>  // printf(), perror()
#include <stdlib.h> // calloc(), exit(), EXIT_FAILURE

int main( void )
{
    char *f = calloc( 1, sizeof(unsigned int) );
    if( !f )
    {
        perror( "calloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, calloc successful

    // f[sizeof(unsigned int)-1] = 0x01; // if big Endian
    f[0] = 0x01;   // assume little Endian/Intel x86 or similar
    unsigned int j = *(unsigned int*)f;
    printf("%u\n", j);
}

編譯/鏈接后,將輸出以下內容:

1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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