通过更高级别的结构访问子变量

Ste*_*art 16 c c++

如果我有这些结构:

typedef struct { int x; } foo;
typedef struct { foo f; } bar;
Run Code Online (Sandbox Code Playgroud)

通常你会获得x通过b.f.x,但有一种方法来设置此,以便您可以访问元素x没有提及f

bar b;
b.x = ...
Run Code Online (Sandbox Code Playgroud)

我的第一个直觉是你不能,因为如果两个子结构都有一个成员x并且我无法弄清楚编译错误是什么,那么就有可能发生名称冲突.但是,我记得在一些可行的框架中工作.

在C++中,我曾在一个bar存在的框架中工作,并且您可以this->x从其他类访问其成员作为成员变量.我想弄清楚如何做到这一点.

小智 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);
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是不同的编译器在我的测试中不同意typedef是否可以作为没有标记结构说明符接受标准指定:

§6.7.8 - 3

在存储类说明符为的typedef声明中,每个声明符都将标识符定义为typedef名称,该名称表示以6.7.6中描述的方式为标识符指定的类型.[...]一个typedef声明不引入新的类型,只有这么指定类型的代名词.

(强调我的) - 但同义词是否也意味着typdef-name说明符可以替换为结构说明符gcc接受这个,clang没有.

当然,没有办法用这些声明来表达整个类型的成员foo,你牺牲了你的命名成员f.

关于你对名称冲突的疑问,gcc当你把另一个int x放在里面时,这是必须要说的bar:

structinherit.c:4:27: error: duplicate member 'x'
 typedef struct { foo; int x; } bar;
                           ^
Run Code Online (Sandbox Code Playgroud)

为了避免歧义,你可以重复结构,可能#defined作为宏,但当然,这看起来有点难看:

#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);
}
Run Code Online (Sandbox Code Playgroud)

任何符合标准的编译器都应接受此代码,因此请坚持使用此版本.

<意见>这是一个遗憾,我喜欢接受的语法gcc要好得多,但由于标准的措辞没有明确允许这个,唯一安全的选择是假设它是被禁止的,所以clang不要责怪这里... </看来>

如果你想指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
}
Run Code Online (Sandbox Code Playgroud)

不会导致别名问题,因为

§6.5.2.3 - 6

为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,则允许检查公共其中任何一个的初始部分都可以看到完整类型的联合声明.如果对应的成员具有一个或多个初始成员的序列的兼容类型(并且对于位字段,具有相同的宽度),则两个结构共享共同的初始序列


Yuk*_*uki 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;
}
Run Code Online (Sandbox Code Playgroud)

在C11之前,匿名结构是标准的广泛扩展.

C++:与C中相同,你可以在这里做,但匿名结构不是任何C++标准的一部分,而是扩展.更好地使用继承,或者根本不使用此快捷方式.

当然,不要使用像#define x b.x)).


dbu*_*ush 5

在C中,您无法访问此类成员.

但是,您可以访问匿名内部结构的成员:

struct bar {
    struct {
        int x;
    }
};

...
struct bar b;
b.x = 1;
Run Code Online (Sandbox Code Playgroud)

在C++中,您使用继承:

struct foo {
    int x;
};

struct bar: public foo {
};

...
struct bar b;
b.x = 1;
Run Code Online (Sandbox Code Playgroud)