我试图在结构中分配char
数组值并检索数据,但检索时遇到一些问题。
struct first {
int a;
int b;
};
struct second {
int c;
int d;
struct first * f_t[2];
};
int main()
{
struct second *p;
char a[24] = {1, 0, 0, 0,
2, 0, 0, 0,
3, 0, 0, 0,
4, 0, 0, 0,
5, 0, 0, 0,
6, 0, 0, 0};
p = (struct second *)a;
p->f_t[0] = (struct first *) (a + 8);
p->f_t[1] = (struct first *) (a + 16);
printf("%d %d %d %d %d %d",
p->c, p->d, p->f_t[0]->a, p->f_t[0]->b, p->f_t[1]->a, p->f_t[1]->b);
}
输出:
1 2 1245008 1245016 1245024 6
前两个值正确出现(1
和2
),但其余值似乎有些垃圾值。
请帮助识别一些错误的初始化方法或其他相同方法。
答案 0 :(得分:0)
首先,永远不要假定结构中的填充。它的运行相当可靠,但是从技术上来说是未定义的行为。
更重要的是,您正在违反严格的别名规则。编译器假设您永远不会使用不同类型的指针(在这种情况下为struct first*
和char*
)访问同一内存位置。您可以使用-fno-strict-aliasing
来解决此问题,也可以使用联合来进行类型校正(通常被称为类型校正)。转到here了解更多信息。
此代码的更正确版本为-
#include <stdio.h>
#include <stdlib.h>
#include <alloca.h>
#include <string.h>
struct first {
int a;
int b;
};
struct second {
int c;
int d;
struct first * f_t[2];
};
int main()
{
struct second *p;
char a[24] = {1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0};
p = alloca(sizeof(struct second));
memset(p, 0, sizeof(struct second));
memcpy(p, a, sizeof(int)*2);
p->f_t[0]= alloca(sizeof(struct first));
p->f_t[1]= alloca(sizeof(struct first));
memset(p->f_t[1], 0, sizeof(struct first));
memset(p->f_t[0], 0, sizeof(struct first));
memcpy(p->f_t[0], a + 8, sizeof(struct first));
memcpy(p->f_t[1], a + 16, sizeof(struct first));
printf("%d %d %d %d %d %d",p->c,p->d,p->f_t[0]->a,p->f_t[0]->b,p->f_t[1]->a,p->f_t[1]->b);
}
注意:使用alloca()
是错误的做法。除非您知道自己在做什么,否则不要使用它。在这里很好,因为它只是在堆栈上分配的一个小结构,但通常避开它,而使用malloc()
或仅使用局部变量。
从技术上讲,这仍然属于未定义的行为,因为我们假设如何填充结构,这是特定于实现的,但是大多数平台使用自对齐数据类型,并且在使用正确对齐的结构时速度要快得多,因此很容易猜测。有关更多信息,请转到here。 我仍然不鼓励这样做,因为这是未定义的行为,很容易弄乱。
此外,下次,请确保提供一个最小,完整和可编译的示例。
答案 1 :(得分:0)
好吧,严格的别名规则,可能的填充,变量大小,对齐方式会带来很多(潜在)问题。
但是,假设您的编译器设置为no-strict-aliasing,并且所有大小,填充和对齐方式都匹配。
然后看看这些行:
p->f_t[0]=(Struct first *) (a+8);
p->f_t[1]=(Struct first *) (a+16);
他们将要做的是覆盖a[8]
并使用指针的值(即地址)转发。因此,a
不再等于初始化值。
尝试一下以了解自己的情况:
// Print all element in a
p->f_t[0]=(Struct first *) (a+8);
// Print all element in a
p->f_t[1]=(Struct first *) (a+16);
// Print all element in a
因此,您的问题是您尝试使用a[8] to a[23]
进行存储
a)两个指针
和
b)首先两个结构
不可能的原因
答案 2 :(得分:0)
其他评论和帖子已经解决了将一种类型转换为另一种类型所伴随的 strict aliasing 问题,并且还详细介绍了其他问题。
从您现有的代码看来,您正在尝试使用struct
引用pointer variables
数组的每个成员。
此答案仅限于以简单的方式说明我认为您想做的事情:(请阅读有关移植物的嵌入式注释)
typedef struct { //using struct instead of Struct
int a;
int b;
}FIRST; //create typedef tag (improved readability throughout code)
typedef struct {
int c;
int d;
FIRST f_t[2]; // changed from *[] to []
}SECOND; // (the rest of your post indicates that is what you meant)
int main()
{
SECOND *p1; //for illustration, create two pointers to reference 2 elements of arr[2]
SECOND *p2;
//Create array of SECOND, populate with unique values in each location
//to provide verification during printf that assignments were made correcly.
SECOND arr[2] = {{1,2,{3,4,5,6}},{7,8,{9,10,11,12}}};
//note values are arranged to follow the definitions of 2 elements of SECOND arr[2].
//Create 2 pointers, 1 for each element of SECOND arr[2]
p1 = &arr[0]; //assigns address of 1st element of SECOND arr[0], to pointer p1
p2 = &arr[1];//assigns address of 1st element of SECOND arr[1], to pointer p2
printf("Elements of p1[0]:\n%d, %d, %d, %d, %d, %d\n", p1[0].c, p1[0].d, p1[0].f_t[0].a,p1[0].f_t[0].b,p1[0].f_t[1].a,p1[0].f_t[1].b );
printf("Elements of p2[0]:\n%d, %d, %d, %d, %d, %d\n", p2[0].c, p2[0].d, p2[0].f_t[0].a,p2[0].f_t[0].b,p2[0].f_t[1].a,p2[0].f_t[1].b );
getchar();//stop execution to view result (needed in my environment)
}