如果我有这些结构:
typedef struct { int x; } foo;
typedef struct { foo f; } bar;
通常您可以通过x
访问b.f.x
,但有没有办法进行设置,以便您可以访问元素x
而无需引用f
?
bar b;
b.x = ...
我的第一个直觉是你不能,因为如果两个子结构都有一个成员x而我无法弄清楚编译错误会是什么,那么就有可能发生名称冲突。但是,我记得在一些可行的框架中工作。
在C ++中,我曾在bar
存在的框架中工作,您可以从其他类访问其成员作为成员变量this->x
。我想弄清楚如何做到这一点。
答案 0 :(得分:18)
你可以使用C11:
§6.7.2.1 - 11
一个未命名的成员,其类型说明符是一个没有标记的结构说明符,称为 匿名结构;一个未命名的成员,其类型说明符是一个联合说明符 没有标签被称为匿名联盟。匿名结构或联合的成员 被认为是包含结构或联合的成员。这适用 如果包含的结构或联合也是匿名的,则递归地进行。
所以这段代码可能工作:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct { foo; } bar;
int main(void)
{
bar b;
b.x = 1;
printf("%d\n", b.x);
}
这里的问题是不同的编译器在我的测试中不同意 typedef 是否可以作为结构说明符而没有标记标准指定:
§6.7.8 - 3
在存储类说明符为
typedef
的声明中,每个声明符定义一个 标识符是typedef名称,表示在路上为标识符指定的类型 在6.7.6中描述。 [...]typedef
声明不会引入新类型,只会 a 所指定类型的同义词。
(强调我的) - 但同义词是否意味着 typdef-name 说明符可以替换为结构说明符? gcc
接受此操作,clang
没有。
当然,没有办法用这些声明来表达类型foo
的整个成员,你牺牲了你的命名成员f
。
关于您对名称冲突的疑问,当您在gcc
内放置另一个int x
时,bar
必须说明这一点:
structinherit.c:4:27: error: duplicate member 'x'
typedef struct { foo; int x; } bar;
^
为了避免含糊不清,你可以重复结构,可能#define
d作为一个宏,但当然,这看起来有点难看:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct { struct { int x; }; } bar;
int main(void)
{
bar b;
b.x = 1;
printf("%d\n", b.x);
}
但任何符合标准的编译器都应接受此代码,因此请坚持使用此版本。
&lt; views&gt;这很遗憾,我更喜欢gcc
接受的语法,但是由于标准的措辞不能使显式允许这样做,唯一的安全赌注是假设它是被禁止的,所以clang
不应该责备在这里......&lt; / opinion&gt;
如果您想通过 x
或 b.x
引用b.f.x
,则可以使用其他匿名联盟这样:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct {
union { struct { int x; }; foo f; };
} bar;
int main(void)
{
bar b;
b.f.x = 2;
b.x = 1;
printf("%d\n", b.f.x); // <-- guaranteed to print 1
}
由于
,不会导致别名问题§6.5.2.3 - 6
为了简化联合的使用,我们做了一个特别的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,则允许检查其中任何一个的共同初始部分,可以看到完整类型的联合声明。如果相应的成员具有一个或多个初始成员的序列的兼容类型(并且对于位字段,具有相同的宽度),则两个结构共享共同的初始序列
答案 1 :(得分:7)
C :非常不推荐,但可行:
#include <stdio.h>
#define BAR_STRUCT struct { int x; }
typedef BAR_STRUCT bar;
typedef struct {
union {
bar b;
BAR_STRUCT;
};
} foo;
int main() {
foo f;
f.x = 989898;
printf("%d %d", f.b.x, f.x);
return 0;
}
匿名结构是C11之前标准的广泛扩展。
<强> C ++ 强>: 与C中相同,你可以在这里做,但匿名结构不是任何C ++标准的一部分,而是扩展。 更好地使用继承,或者根本不使用此快捷方式。
当然,不要使用类似#define x b.x
)的内容。
答案 2 :(得分:5)
在C中,您无法访问此类成员。
但是,您可以访问匿名内部结构的成员:
struct bar {
struct {
int x;
}
};
...
struct bar b;
b.x = 1;
在C ++中,您使用继承:
struct foo {
int x;
};
struct bar: public foo {
};
...
struct bar b;
b.x = 1;
答案 3 :(得分:3)
在C(99及以后)中,您可以访问联合成员的公共初始子序列,即使它们不是写入 1 的最后一个成员。
在C11中,您可以拥有匿名工会成员。所以:
typedef struct { int x; } foo;
typedef struct {
union {
foo f;
int x;
};
} bar;
答案 4 :(得分:2)
这在C语言中是不可能的。但是在C ++中你可以使用继承,这可能就是你想到的。
答案 5 :(得分:2)
在C ++中,您可以使用继承,并且成员名称冲突可以与::
一起解析,并将基类视为成员。
struct foo { int x; };
struct bar : foo { };
struct foo1 { int x; };
struct bar1 : foo1 { char const* x; };
bar b;
bar1 b1;
int main()
{
return b.x + b1.foo1::x;
}
在标准C中,它是不可能的,但是一些编译器(gcc,clang,tinycc)支持与扩展类似的东西(通常可以通过-fms-extensions
访问(在gcc上也可以-fplan9-extensions
这是-fms-extensions
))的超集,允许你这样做:
struct foo { int x; };
struct bar { struct foo; };
struct bar b = { 42 };
int main()
{
return b.x;
}
但是,没有解决与之相冲突的成员名称,AFAIK。
答案 6 :(得分:0)
在C ++中,它有两种可能。首先是使用继承。第二个是import {Header} from './Header.jsx';
包含名为bar
(x
)的引用成员,以及初始化int &x
以引用x
的构造函数。
在C中,这是不可能的。
答案 7 :(得分:0)
由于C标准保证在结构的第一个成员之前没有填充,因此在foo
中的bar
之前没有填充,并且在x
之前没有填充在foo
中{1}}。因此,bar
开头的原始内存访问权限将访问bar::foo::x
。
你可以这样做:
#include <stdio.h>
#include <stdlib.h>
typedef struct _foo
{
int x;
} foo;
typedef struct _bar
{
foo f;
} bar;
int main()
{
bar b;
int val = 10;
// Setting the value:
memcpy(&b, &val, sizeof(int));
printf("%d\n", b.f.x);
b.f.x = 100;
// Reading the value:
memcpy(&val, &b, sizeof(int));
printf("%d\n", val);
return 0;
}
正如其他人所说,C ++通过继承提供了一种更优雅的方式。