我的好奇心受到以下代码的影响:
struct tree
{
unsigned char apple, leaf;
};
int main(void)
{
void* arr[2] = {(int*)1, (int*)2};
struct tree* myStruct = (struct tree*)arr;
return 1;
}
..逻辑上尝试将数组转换为结构并且不会发出警告。
这是我将数组转换为结构的方式吗?
答案 0 :(得分:4)
逻辑上尝试将数组转换为结构并且不会发出警告。
该代码背后没有任何逻辑。更准确地说,代码无意义尝试将数组转换为结构。但是,C允许很多废话,当你调用未定义的行为时,一切都会发生。
这就是线后面发生的事情:
void* arr[2]
是一个由两个指针组成的数组,它们的大小与给定系统的地址总线大小相同。我们假设地址总线是32位。{(int*)1, (int*)2};
然后获取两个整数文字并将它们中的每一个转换为指针。这在C中很好。所以我们有两个指针分别地址为0x00000001和0x00000002。 (struct tree*)arr
疯狂地将数组转换为结构类型。这打破了所谓的"strict aliasing rule"和这是未定义的行为。在这里你的程序可能会崩溃和烧毁,因为有几个潜在的问题。 char
在给定系统上的表示可能是任何内容。它们可能是8位,可能是16位,它们可能带有或不带有符号位。apple
和leaf
将分别包含值0和0。但这也是依赖于endianess的,指针地址中的哪个字节取决于你的机器是使用小端还是大端。这是我将数组转换为结构的方式吗?
不,这是非常糟糕的代码。没有什么是正确的。永远不要写这样的代码。
那么将数组转换为结构的正确方法是什么?
简单地说:
char arr[2] = {1, 2};
myStruct.apple = arr[1];
myStruct.leaf = arr[2];
这是唯一的100%防弹方式。如果你想使用memcpy()或类似的东西,为了减少手动分配的数量,你必须编写防御性编程以保护自己免受struct padding:
static_assert(sizeof(arr) == sizeof(myStruct), "ERR: struct padding detected");
memcpy(&myStruct, arr, sizeof(myStruct));
答案 1 :(得分:1)
您将变量arr
定义为void *
。在C中,void指针用于定义泛型类型。您可以将void *
投射到您想要的任何内容。这就是为什么没有警告。
但请记住,现代32/64位系统上的指针大小为4或8字节。您的结构tree
小于数组arr
。
我认为你想要它(适用于32位系统):
#include <stdio.h>
struct tree
{
// use int instead of char because char is only 1 byte
// if 32 bit system
unsigned int apple, leaf;
// if 64 bit system
// unsigned long apple, leaf;
};
int main(void)
{
void* arr[2] = {(int*)1, (int*)2};
struct tree* myStruct = (struct tree*)arr;
// if 32 bit system
printf("%d\n", myStruct->apple);
printf("%d\n", myStruct->leaf);
// if 64 bit system
//printf("%lu\n", myStruct->apple);
//printf("%lu\n", myStruct->leaf);
return 1;
}
此示例不适用于每个系统,并且由于struct成员对齐而具有未定义的行为。阅读Lundin的帖子了解更多信息。
答案 2 :(得分:0)
#include <stdio.h>
struct tree
{
char apple, leaf;
};
int main(void)
{
char arr[sizeof(struct tree)] = {'1', '2'}; //array of pointers it is ugly
//use char or unsigned char, and size of array must be "sizeof(struct tree)"
//cause struct may be alligned
struct tree* myStruct = (struct tree*)arr;
printf("%p\n", myStruct);
printf("%c\n", myStruct->apple);
printf("%c\n", myStruct->leaf);
return 1;
}
工作正常