是否可以将不同的数据类型存储在C中相同的已分配内存中?

我想在同一个分配的内存中存储不同的数据类型,以便通过仅分配一次内存来减少执行时间。 我发现实际上可以创建一个uint8_t变量数组并创建一个指向同一内存地址的新uint16_t指针,然后我可以双向读取这些值。

这允许我创建一个指针,让我们说分配内存的中间,并将值存储在后半部分的不同数据类型中。

可以这样做吗? 我知道我需要关注内存边界,但这种风格是不是很糟糕?

这是我的代码:

 #include  #include  #include  #include  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; } 

使用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]); ... 

可以这样做吗?

标准说:

指向对象类型的指针可以转换为指向不同对象类型的指针。 如果生成的指针未针对引用的类型正确对齐,则行为未定义。 否则,当再次转换回来时,结果应该等于原始指针。

(C2011,6.3.2.3/7)

请注意,您甚至不必使用转换后的指针来产生未定义的行为 – 转换本身的行为是未定义的。

话虽如此,您的示例代码展示了一个特殊情况:成功调用calloc() (或malloc()realloc() )返回的指针保证适当地对齐任何类型的对象,因此特定指针你执行的转换( array2 = &array[0] )应该总是正常的。 但是,它应该需要演员。 你的编译器应该警告你。

如果您计划将指针转换为已分配块内部的任意位置,则不能依赖对齐是正确的。

另请注意,使用此方案可能会危害性能而不是改进性能。 特别是,某些处理器对于适当对齐的数据具有更好的加载和存储性能,即使它们可以处理其他对齐。 您需要为每个块支付一次内存分配成本 – 您需要为每次访问支付任何未对齐访问权限。

我知道我需要关注内存边界,但这种风格是不是很糟糕?

是的,非常。 您正在牺牲代码清晰度来获得不确定的假设性能增益。 增加的开发和维护成本可能会淹没任何性能提升,特别是因为您也混淆了编译器的意图,从而使生成高效的机器代码变得更加困难。

而且,从这种微优化开始可能还为时过早。 首先让你的程序正常工作。 如果它不够快,请测试找出瓶颈并专注于改进这些部件。 您最有可能通过选择更好的算法来提高性能; 像你提出的小技巧很少值得。