2015-12-31 33 views
8

我想將不同的數據類型存儲在同一個分配的內存中,通過只分配一次內存來減少執行時間。我發現實際上可以創建一個uint8_t變量的數組,並創建一個新的uint16_t指向相同內存地址的指針,然後我可以兩種方式讀取這些值。可以將不同的數據類型存儲在C中相同的分配內存中嗎?

這允許我創建一個指針,讓我們說分配的內存的中間,並將數據的後半部分存儲在不同的數據類型中。

這樣可以嗎?我知道我需要關注記憶界限,但這是不好的風格?

這裏我的代碼:

#include <stdio.h> 
#include <inttypes.h> 
#include <stdint.h> 
#include <stdlib.h> 

int main(void){ 
    uint8_t *array; 
    uint16_t *array2; 
    array = calloc(6, 1); 
    array[0] = 257; 

    printf("array[0]= %" PRIu8 "\n", array[0]); 
    printf("array[1]= %" PRIu8 "\n", array[1]); 
    printf("Adresse von array[0] = %p\n", &array[0]); 
    array2 = &array[0]; 
    printf("Adresse auf die array2 zeigt = %p\n", array2); 

    array2[0] = 257; 
    printf("array2[0]= %" PRIu16 "\n", array2[0]); 
    printf("array2[1]= %" PRIu16 "\n", array2[1]); 
    printf("array[0]= %" PRIu8 "\n", array[0]); 
    printf("array[1]= %" PRIu8 "\n", array[1]); 

    getchar(); 
    return 0; 
} 
+8

閱讀關於union –

+0

但實際上你並沒有在同一個分配的內存中存儲不同數據類型的dada。 – ameyCU

+4

由於數據類型可能有不同的內存對齊要求,因此手動執行此操作是一種不好的做法。使用「聯合」。 – kfx

回答

10

使用union創建一個變量,有時存儲一個類型,有時另一個。

union { 
    uint8_t u8; 
    uint16_t u16; 
} *array_u; 
size_t nmemb = 6; 

array_u = calloc(nmemb, sizeof *array_u); 
assert(array_u); 

printf("array_u[0].u8 = %" PRIu8 "\n", array_u[0].u8); 

array_u[0].u16 = 1234; 
printf("array_u[0].u16 = %" PRIu16 "\n", array_u[0].u16); 
... 

這並不使用所有的空間,每個聯合只有一個uint8_t u8。以下使用2 uint8_t

union { 
    uint8_t u8[2]; 
    uint16_t u16; 
} *array_u; 

printf("array_u[0].u8[0] = %" PRIu8 "\n", array_u[0].u8[0]); 

array_u[0].u16 = 1234; 
printf("array_u[0].u16 = %" PRIu16 "\n", array_u[0].u16); 

OTOH如果代碼需要覆蓋固定長度

union { 
    uint8_t u8[12]; 
    uint16_t u16[6]; 
} *array_u; 

array_u = calloc(1, sizeof *array_u); 
assert(array_u); 

printf("array_u->u8[0] = %" PRIu8 "\n", array_u->u8[0]); 

array_u->u16[0] = 1234; 
printf("array_u->u16[0] = %" PRIu16 "\n", array_u->u16[0]); 
... 
+0

很好的答案!非常感謝! 'array_u-> u16 [0]'和'array_u [0] .u16 [0]'是否有區別? – TimFinnegan

+2

@TimFinnegan'array_u-> u16 [0]'和'array_u [0] .u16 [0]'之間沒有功能上的區別。使用最能表達代碼含義的表單。 – chux

4

的整個數組是好一些呢?

標準表示:

一個指向對象類型可被轉換成一個指針到一個不同的對象類型。如果生成的指針未針對引用類型正確對齊,則行爲未定義。否則,當再次轉換時,結果應與原始指針相等。

(C2011,6.3.2.3/7)

注意,你甚至不用到使用轉換後的指針產生不確定的行爲 - 轉換本身的行爲是不確定的。

隨着中說,您的示例代碼顯示出一種特殊情況:通過成功調用calloc()(或malloc()realloc())返回的指針是保證任何類型的一個目的是適當地對準,使得所述特定的指針轉換你執行(array2 = &array[0])應該總是好的。但是,它應該需要演員。你的編譯器應該警告你。

如果您計劃將指針轉換爲分配塊內部的任意位置,則不能依賴對齊來正確對齊。

還請注意,使用此方案您可能會損害性能而不是改善性能。特別是,一些處理器對於適當對齊的數據具有更好的加載和存儲性能,即使它們可以處理其他對齊。您每塊支付一次內存分配成本 - 您支付每次訪問時未對齊訪問的任何成本。

我知道我需要關注記憶的界限,但這是不好的風格?

是的,很。您爲了不確定的假設性能增益而犧牲代碼清晰度。增加的開發和維護成本可能會大大增加性能,尤其是因爲您也在混淆編譯器的意圖,從而導致難以生成高效的機器代碼。

此外,從這種微觀優化開始可能還爲時過早。首先讓你的程序正確工作。如果速度不夠快,測試找到瓶頸,並專注於改善這些部分。您最有可能通過選擇更好的算法來提高性能;你提出的一些小竅門很少值得。

+1

對問題的良好分析。 – chux

相關問題