【发布时间】:2021-08-05 04:12:27
【问题描述】:
我有一个静态分配的字符数组。我可以在不违反严格的别名规则的情况下重用这个数组来存储不同的类型吗?我不太了解严格的别名,但这是我想做的代码示例:
#include <stdio.h>
static char memory_pool[256 * 1024];
struct m1
{
int f1;
int f2;
};
struct m2
{
long f1;
long f2;
};
struct m3
{
float f1;
float f2;
float f3;
};
int main()
{
void *at;
struct m1 *m1;
struct m2 *m2;
struct m3 *m3;
at = &memory_pool[0];
m1 = (struct m1 *)at;
m1->f1 = 10;
m1->f2 = 20;
printf("m1->f1 = %d, m1->f2 = %d;\n", m1->f1, m1->f2);
m2 = (struct m2 *)at;
m2->f1 = 30L;
m2->f2 = 40L;
printf("m2->f1 = %ld, m2->f2 = %ld;\n", m2->f1, m2->f2);
m3 = (struct m3 *)at;
m3->f1 = 5.0;
m3->f2 = 6.0;
m3->f3 = 7.0;
printf("m3->f1 = %f, m3->f2 = %f, m3->f3 = %f;\n", m3->f1, m3->f2, m3->f3);
return 0;
}
我使用 gcc 和 -Wstrict-aliasing=3 -fstrict-aliasing 编译了这段代码,它按预期工作:
m1->f1 = 10, m1->f2 = 20;
m2->f1 = 30, m2->f2 = 40;
m3->f1 = 5.000000, m3->f2 = 6.000000, m3->f3 = 7.000000;
该代码安全吗?假设memory_pool 总是足够大。
【问题讨论】:
-
你为什么不直接使用联合?
-
我不是专家也不是语言律师,但我相信这是 UB,因为别名涉及多个名称相同类型被用来指代相同的内存位置- 因为您使用不同的类型,这使得它更像
union- 在这种情况下,您应该特别使用union。 -
@BillLynch 这样做和使用
union有什么区别吗? -
@valentinsp 实际上,如果您使用一些翻译单元隔离,大多数编译器将无法知道
void *myalloc(void);或某些extern char *myblock;是否会返回具有声明类型的指针或不是,所以他们必须保守地将通过它的访问视为对没有声明类型的内存的访问(即使该类型是在某些不可访问的翻译单元中声明的)。 -
@PSkocik -- 是的,这就是我提供的链接的确切部分...
"An object shall have its stored value accessed only by an lvalue expression that has one of the following types: --- a character type"。是的,对此有很多讨论,但都以有限的不确定性告终。在这里,您有一个内存块,用于存储char类型的块。它可以通过对象类型或char类型访问。将其放入 char 块将需要memcpy(),这在 (P6) 中进行了讨论。还有关于访问是否会修改对象的警告。
标签: c language-lawyer strict-aliasing memory-pool