包含包含指向自身的结构指针的联合的结构使用“。”访问而不是'->',混淆
Struct containing union containing struct pointer to self uses '.' access instead of '->', confused
在我正在处理的代码库中,我定义了两个结构,如下所示:
typedef struct s1
{
int somedata;
union su
{
char *cptr;
struct s1 *array;
}; //line 123
} S1;
typedef struct s2
{
S1 data;
} S2;
在其他地方,这些结构和成员的访问方式让我感到困惑:
S2 *s2_ptr;
s2_ptr->data.array[1].charptr
所以我有问题:
为什么是 array[1].charptr
而不是 array[1]->charptr
因为 array
是一个指针?
编译时,我在上面的结构 s1
中的 "line 123" 上收到警告 "declaration does not declare anything"。我已经阅读了有关此的其他问题,看来我需要使联合声明类似于:
union su
{
...
} SU;
然后由于明显的原因导致编译器错误。当然,然后更正对 s2_ptr->data.SU.array[1].charptr
的调用可以修复错误。我想知道这是否会以任何方式改变数据访问方式中发生的事情?会有什么变化吗?
感谢您的帮助。
*非常感谢您的所有回答。把我清理干净了。
Why is it array[1].charptr
and not array[1]->charptr
since array is a pointer?
array[1]
不是指针。
如果代码是 array->charptr
那么你是对的;但事实并非如此。 array[1]
是一个 struct s1
。 (这与工会无关)
你问题的另一部分:当你有这样的代码时:
union foo
{
int x;
// etc
};
然后这定义了一个名为 union foo
的 类型 ,但没有声明该类型的任何实例。如果您在结构定义中,那不会改变。
要声明变量,您必须编写:
union foo SU;
或者您可以通过将变量名放在类型定义末尾的 ;
之前来同时完成这两件事。
C11 中有一个名为 anonymous unions 的东西,在此之前由一些编译器作为扩展提供。但是,要激活匿名联合,您必须取出联合标记,因此代码以 union {
打开。
编译器报错,因为你没有声明联合成员,你只是在定义联合。
你的结构和联合是相互依赖的。解决这个问题的最好方法是先制作原型:
union myUnion;
struct myFistStruct;
struct mySecondStruct;
然后你就可以正确定义它们了:
union myUnion
{
char *pC;
struct myFistStruct *pS1;
};
struct myFistStruct
{
int D;
union myUnion U;
};
struct mySecondStruct
{
struct myFistStruct S1;
};
关于 .
和 ->
运算符。一个单一的规则,你永远不会感到困惑;让我们考虑这个表达式:
(左操作数)(运算符)(右操作数)
如果左操作数是结构或联合本身,则运算符是 (.
),如果左操作数是指向结构或联合的指针,则运算符是 (->
).
因此有效的访问表达式如下:
struct mySecondStruct *pS2 = (struct mySecondStruct*)malloc(sizeof(struct mySecondStruct));
// pS2->S1
// pS2->S1.D
// pS2->S1.U
// pS2->S1.U.pC
// pS2->S1.U.pS1
union
问题已经解决,但是(到目前为止)我没有看到对你的指针/数组表示法问题的很好解释:
Why is it array[1].charptr and not array[1]->charptr since array is a
pointer?
array
确实是一个指针,并且 大概 (但不是在您发布的代码中)它被初始化为指向一个足够大的内存块对于至少 2 s1
个对象。当代码引用 s2_ptr->data.SU.array
时(当然要加上 union 字段名)那么你指的是指向这块内存的指针,它可以看作是 s1
对象的数组。所以 s2_ptr->data.SU.array[1]
指的是该数组中的第二个对象。由于您指的是特定对象,因此您使用点符号来访问其字段 - s2_ptr->data.SU.array[1].charptr
。
如果您想访问该数组中的 first 对象,您可以使用 s2_ptr->data.SU.array->charptr
或 s2_ptr->data.SU.array[0].charptr
。
C 提供了几种解引用指针的方法,即通过指针访问特定对象:*p
、p->
、p[i]
都是非常密切相关的解引用操作。
在我正在处理的代码库中,我定义了两个结构,如下所示:
typedef struct s1
{
int somedata;
union su
{
char *cptr;
struct s1 *array;
}; //line 123
} S1;
typedef struct s2
{
S1 data;
} S2;
在其他地方,这些结构和成员的访问方式让我感到困惑:
S2 *s2_ptr;
s2_ptr->data.array[1].charptr
所以我有问题:
为什么是 array[1].charptr
而不是 array[1]->charptr
因为 array
是一个指针?
编译时,我在上面的结构 s1
中的 "line 123" 上收到警告 "declaration does not declare anything"。我已经阅读了有关此的其他问题,看来我需要使联合声明类似于:
union su
{
...
} SU;
然后由于明显的原因导致编译器错误。当然,然后更正对 s2_ptr->data.SU.array[1].charptr
的调用可以修复错误。我想知道这是否会以任何方式改变数据访问方式中发生的事情?会有什么变化吗?
感谢您的帮助。
*非常感谢您的所有回答。把我清理干净了。
Why is it
array[1].charptr
and notarray[1]->charptr
since array is a pointer?
array[1]
不是指针。
如果代码是 array->charptr
那么你是对的;但事实并非如此。 array[1]
是一个 struct s1
。 (这与工会无关)
你问题的另一部分:当你有这样的代码时:
union foo
{
int x;
// etc
};
然后这定义了一个名为 union foo
的 类型 ,但没有声明该类型的任何实例。如果您在结构定义中,那不会改变。
要声明变量,您必须编写:
union foo SU;
或者您可以通过将变量名放在类型定义末尾的 ;
之前来同时完成这两件事。
C11 中有一个名为 anonymous unions 的东西,在此之前由一些编译器作为扩展提供。但是,要激活匿名联合,您必须取出联合标记,因此代码以 union {
打开。
编译器报错,因为你没有声明联合成员,你只是在定义联合。
你的结构和联合是相互依赖的。解决这个问题的最好方法是先制作原型:
union myUnion;
struct myFistStruct;
struct mySecondStruct;
然后你就可以正确定义它们了:
union myUnion
{
char *pC;
struct myFistStruct *pS1;
};
struct myFistStruct
{
int D;
union myUnion U;
};
struct mySecondStruct
{
struct myFistStruct S1;
};
关于 .
和 ->
运算符。一个单一的规则,你永远不会感到困惑;让我们考虑这个表达式:
(左操作数)(运算符)(右操作数)
如果左操作数是结构或联合本身,则运算符是 (.
),如果左操作数是指向结构或联合的指针,则运算符是 (->
).
因此有效的访问表达式如下:
struct mySecondStruct *pS2 = (struct mySecondStruct*)malloc(sizeof(struct mySecondStruct));
// pS2->S1
// pS2->S1.D
// pS2->S1.U
// pS2->S1.U.pC
// pS2->S1.U.pS1
union
问题已经解决,但是(到目前为止)我没有看到对你的指针/数组表示法问题的很好解释:
Why is it array[1].charptr and not array[1]->charptr since array is a pointer?
array
确实是一个指针,并且 大概 (但不是在您发布的代码中)它被初始化为指向一个足够大的内存块对于至少 2 s1
个对象。当代码引用 s2_ptr->data.SU.array
时(当然要加上 union 字段名)那么你指的是指向这块内存的指针,它可以看作是 s1
对象的数组。所以 s2_ptr->data.SU.array[1]
指的是该数组中的第二个对象。由于您指的是特定对象,因此您使用点符号来访问其字段 - s2_ptr->data.SU.array[1].charptr
。
如果您想访问该数组中的 first 对象,您可以使用 s2_ptr->data.SU.array->charptr
或 s2_ptr->data.SU.array[0].charptr
。
C 提供了几种解引用指针的方法,即通过指针访问特定对象:*p
、p->
、p[i]
都是非常密切相关的解引用操作。