Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
137 views
in Technique[技术] by (71.8m points)

c++ - Accessing child variables through higher level structures

If I have these structures:

typedef struct { int x; } foo;
typedef struct { foo f; } bar;

Normally you would access x through b.f.x, but is there a way to set this up so that you can access element x without referring to f?

bar b;
b.x = ...

My first intuition is that you can't since there would be a possibility for name conflicts if two sub structures both had a member x and I can't figure out what the compile error would be. However, I recall working in some frameworks where this was possible.

In C++ I worked in a framework once where bar existed, and you could access its members as member variables this->x from a different class. I'm trying to figure out how that could be done.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can with C11:

§ 6.7.2.1 -- 11

An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

So this code might work:

#include <stdio.h>

typedef struct { int x; } foo;
typedef struct { foo; } bar;

int main(void)
{
    bar b;
    b.x = 1;
    printf("%d
", b.x);
}

The problem here is that different compilers disagree in my tests on whether a typedef is acceptable as a struct specifier with no tag The standard specifies:

§ 6.7.8 -- 3

In a declaration whose storage-class specifier is typedef, each declarator defines an identifier to be a typedef name that denotes the type specified for the identifier in the way described in 6.7.6. [...] A typedef declaration does not introduce a new type, only a synonym for the type so specified.

(emphasis mine) -- But does synonym also mean a typdef-name specifier is exchangeable for a struct specifier? gcc accepts this, clang doesn't.

Of course, there's no way to express the whole member of type foo with these declarations, you sacrifice your named member f.

Concerning your doubt about name collisions, this is what gcc has to say when you put another int x inside bar:

structinherit.c:4:27: error: duplicate member 'x'
 typedef struct { foo; int x; } bar;
                           ^

To avoid ambiguity, you can just repeat the struct, possibly #defined as a macro, but of course, this looks a bit ugly:

#include <stdio.h>

typedef struct { int x; } foo;
typedef struct { struct { int x; }; } bar;

int main(void)
{
    bar b;
    b.x = 1;
    printf("%d
", b.x);
}

But any conforming compiler should accept this code, so stick to this version.

<opinion>This is a pity, I like the syntax accepted by gcc much better, but as the wording of the standard doesn't make it explicit to allow this, the only safe bet is to assume it's forbidden, so clang is not to blame here...</opinion>

If you want to refer to x by either b.x or b.f.x, you can use an additional anonymous union like this:

#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
", b.f.x); // <-- guaranteed to print 1
}

This will not cause aliasing issues because of

§ 6.5.2.3 -- 6

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...