在我正在处理的代码库中,我有两个结构定义如下:
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
是一个指针?
编译时,我收到警告"声明没有声明任何内容"在"第123行"在上面的结构s1
中。我已经阅读了有关此问题的其他问题,似乎我需要将联合声明做为:
union su
{
...
} SU;
然后由于显而易见的原因导致编译错误。当然,更正s2_ptr->data.SU.array[1].charptr
的调用可以修复错误。我想知道这是否会以任何方式改变数据访问方式的变化?会有什么变化吗?
感谢您的帮助。
*非常感谢所有答案。把我清理干净了。
答案 0 :(得分:3)
为什么它是
array[1].charptr
而不是array[1]->charptr
,因为数组是一个指针?
array[1]
不是指针。
如果代码是array->charptr
那么你就是对的;但事实并非如此。 array[1]
是struct s1
。 (这与工会无关)
问题的另一部分:如果你有这样的代码:
union foo
{
int x;
// etc
};
然后这定义了一个名为union foo
的类型,但没有声明该类型的任何实例。如果您在结构定义中,则不会更改。
要声明变量,你必须写:
union foo SU;
或者你可以通过将变量名放在类型定义末尾的;
之前一次完成这两件事。
有一个名为匿名联盟的东西,它在C11中,在此之前由一些编译器作为扩展提供。要激活匿名联合,您必须取出union标记,因此代码将以union {
打开。
答案 1 :(得分:1)
编译器抱怨,因为你没有声明工会成员,你只是定义工会。
你的结构和结合是相互依赖的。解决这个问题的最佳方法是首先对它们进行原型设计:
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
答案 2 :(得分:1)
已经处理了union
个问题,但(到目前为止)我没有看到关于指针/数组符号问题的非常好的解释:
为什么是数组[1] .charptr而不是数组[1] - > charptr因为数组是一个 指针?
array
确实是一个指针,而可能是(但在你发布的代码中没有),它被初始化为指向一个足够大的内存块,至少, 2个s1
个对象。当代码引用s2_ptr->data.SU.array
(当然添加了union字段名称)时,您指的是指向此内存块的指针,可以将其视为s1
个对象的数组。所以s2_ptr->data.SU.array[1]
引用该数组中的第二个对象。由于您指的是特定对象,因此使用点符号来访问其字段 - s2_ptr->data.SU.array[1].charptr
。
如果您想访问该数组中的第一个对象,可以使用s2_ptr->data.SU.array->charptr
或s2_ptr->data.SU.array[0].charptr
。
C提供了几种取消引用指针的方法,即通过指针访问特定对象:*p
,p->
,p[i]
都是非常密切相关的解除引用操作。