2015-12-31 34 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

相关问题