Unnamed members

T

Tom Plunket

The project I'm currently on makes heavy use of unnamed structures to
represent an "object hierarchy" of a sort.

E.g.

struct BaseObject
{
int aMember;
int anotherMember;
// etc.
};

struct GameObject
{
struct BaseObject;

int yetAnotherMember;
// etc.
};

Doing so facilitates the use of the BaseObject's members, so a
function might be able to do:

void fn(GameObject* g)
{
g->aMember = 4;
g->anotherMember = 6;
g->yetAnotherMember = 839;
}

However, coming from a C++ background myself (in recent history,
anyway), this sort of thing horrifies me on many levels. Even when I
was a C programmer exclusively (almost ten years now past!), I never
saw this functionality used on any actual project.

My question, finally, is, "is this sort of thing frequently used by
'real' C programmers?" I suppose the answer may come down to your
view of object oriented concepts, but even from a purely procedural
point of view, I don't like the idea of not being able to easily
figure out where a member actually lives. Bear in mind that this
method is used substantially, and it is not uncommon for an "object
hierarchy" so-constructed to be 10 levels deep. ...that of course
brings with it its own challenges, but I'm mostly interested in how
"real" C coders view unnamed member variables and their use as
demonstrated above.

thanks for any insight,
-tom!
 
L

L7

Tom said:
The project I'm currently on makes heavy use of unnamed structures to
represent an "object hierarchy" of a sort.

E.g.

struct BaseObject
{
int aMember;
int anotherMember;
// etc.
};

struct GameObject
{
struct BaseObject;

int yetAnotherMember;
// etc.
};

Doing so facilitates the use of the BaseObject's members, so a
function might be able to do:

void fn(GameObject* g)
{
g->aMember = 4;
g->anotherMember = 6;
g->yetAnotherMember = 839;
}

However, coming from a C++ background myself (in recent history,
anyway), this sort of thing horrifies me on many levels. Even when I
was a C programmer exclusively (almost ten years now past!), I never
saw this functionality used on any actual project.

My question, finally, is, "is this sort of thing frequently used by
'real' C programmers?" I suppose the answer may come down to your
view of object oriented concepts, but even from a purely procedural
point of view, I don't like the idea of not being able to easily
figure out where a member actually lives. Bear in mind that this
method is used substantially, and it is not uncommon for an "object
hierarchy" so-constructed to be 10 levels deep. ...that of course
brings with it its own challenges, but I'm mostly interested in how
"real" C coders view unnamed member variables and their use as
demonstrated above.

thanks for any insight,
-tom!

Although it is similar, it may be different enough for what you want:

#define COMMON_MEMBERS \
const char * name; \
struct info_t info; \
int type \

Which allows for things such as:

typedef base_type {
COMMON_MEMBERS;
} base_t;

typedef list_type {
COMMON_MEMBERS;
size_t nchildren;
base_t *children[MAX];
} list_t;

typedef something_more_involved {
COMMON_MEMBERS;
char storage[255];
unsigned char IP[4];
int valid;
} extended_t;

enum { THING_BASE,
THING_LIST,
THING_EXTEND,
}

And when you want to use it...

base_t * thing;
thing = (base_t *) CAST_TO_THING (THING_LIST);
 
$

$hiv.....

Tom said:
The project I'm currently on makes heavy use of unnamed structures to
represent an "object hierarchy" of a sort.

E.g.

struct BaseObject
{
int aMember;
int anotherMember;
// etc.
};

struct GameObject
{
struct BaseObject;

int yetAnotherMember;
// etc.
};

Doing so facilitates the use of the BaseObject's members, so a
function might be able to do:

void fn(GameObject* g)
{
g->aMember = 4;
g->anotherMember = 6;
g->yetAnotherMember = 839;
}

However, coming from a C++ background myself (in recent history,
anyway), this sort of thing horrifies me on many levels. Even when I
was a C programmer exclusively (almost ten years now past!), I never
saw this functionality used on any actual project.

My question, finally, is, "is this sort of thing frequently used by
'real' C programmers?" I suppose the answer may come down to your
view of object oriented concepts, but even from a purely procedural
point of view, I don't like the idea of not being able to easily
figure out where a member actually lives. Bear in mind that this
method is used substantially, and it is not uncommon for an "object
hierarchy" so-constructed to be 10 levels deep. ...that of course
brings with it its own challenges, but I'm mostly interested in how
"real" C coders view unnamed member variables and their use as
demonstrated above.

thanks for any insight,
-tom!



hi, u can use them like this

struct BaseObject
{
int aMember2; /*just change to another name */
int anotherMember2;
};

struct GameObject
{
struct BaseObject;
int yetAnotherMember;

/*this can be defined anywhere but for convinience u can write here */
#define aMember BaseObject.aMember2
#define anotherMember BaseObject.anotherMember2
};

Now u can easily make use of these in any function:

void fn(GameObject* g)
{
g->aMember = 4;
g->anotherMember = 6;
g->yetAnotherMember = 839;
}

i think u got ur Solution now...
 
P

Peter Nilsson

Tom said:
The project I'm currently on makes heavy use of unnamed
structures to represent an "object hierarchy" of a sort.

E.g.

struct BaseObject
{
int aMember;
int anotherMember;
// etc.
};

struct GameObject
{
struct BaseObject;
int yetAnotherMember;
// etc.
};
My question, finally, is, "is this sort of thing frequently used by
'real' C programmers?"

The question we can definitively answer in comp.lang.c is "Is this
legal in C?" to which the answer is no, it invokes undefined
behaviour.

Google the archives for unnamed struct members for previous
discussions.
 
F

Frederick Gotham

Tom Plunket posted:

struct GameObject
{
struct BaseObject;

int yetAnotherMember;
// etc.
};


That simply looks like a forward declaration.

Is this the syntax C uses to achieve inheritance? i.e. the C++ equivalent
of:


struct GameObject : BaseObject {

int yet_another_member;
};
 
T

Tom Plunket

Peter said:
The question we can definitively answer in comp.lang.c is "Is this
legal in C?" to which the answer is no, it invokes undefined
behaviour.

Huh, ok. That may be why I've never seen it before. It most
definitely doesn't compile in any of the C++ compilers I've used, but
there are three C compilers in play here at this time, and they're all
happy with this sort of structure. (MSVC.NET's, gcc 2.9something, and
snc from SN Systems.)
Google the archives for unnamed struct members for previous
discussions.

Thanks. Pretty much all I got were rants against typedefs and a
discussion about COBOL. ;) Alas, that it's "undefined" is enough
info for me. I suppose this "extension," then, is to normalize the
behavior of structs and unions in this case, as unnamed unions are
explicitly allowed by the standard, no? If unnamed unions are defined
and structs not, well, then I'm curious as to why, but this may not be
the forum for that answer.
-tom!
 
T

Tom Plunket

L7 said:
Although it is similar, it may be different enough for what you want:

#define COMMON_MEMBERS \
const char * name; \
struct info_t info; \
int type \

That is the most horrifying thing I have ever seen, and if one of my
programmers wrote that, I would fire her immediately.

:)
-tom!
 
T

Tom Plunket

Frederick said:
That simply looks like a forward declaration.

Is this the syntax C uses to achieve inheritance? i.e. the C++ equivalent
of:

struct GameObject : BaseObject {

int yet_another_member;
};

Yep.

Indeed, the code in question often does the following in header files:

typedef struct BaseObject BaseObject;

struct GameObject
{
#ifdef __c_plus_plus // or whatever it is
BaseObject BaseObject;
#else
BaseObject;
#endif

// ...
};

I'm not saying that I support this method of development (quite the
contrary, indeed), but I was looking more for "acceptability" in C
circles. As it appears that this is undefined behavior, I have all of
the answer I need to justify a "stop doing this now" command to the
team. ;) Some defend this as making the code "OO", but I'm sure that
many would agree that "pulling an object's names into another object's
namespace is not the definition of object-oriented." :)
-tom!
 
K

Keith Thompson

It's undefined behavior, not a constraint violation?

[...]
Thanks. Pretty much all I got were rants against typedefs and a
discussion about COBOL. ;) Alas, that it's "undefined" is enough
info for me. I suppose this "extension," then, is to normalize the
behavior of structs and unions in this case, as unnamed unions are
explicitly allowed by the standard, no? If unnamed unions are defined
and structs not, well, then I'm curious as to why, but this may not be
the forum for that answer.

No, unnamed unions are not allowed either, if I understand the term
correctly.

Given this:

struct inner_struct {
int a;
int b;
};

union inner_union {
int c;
int d;
};

struct outer {
struct inner_struct;
union inner_union;
};

both members of "struct outer" are invalid. gcc says:

tmp.c:12: warning: declaration does not declare anything
tmp.c:13: warning: declaration does not declare anything

With "ansi -pedantic", it says:

tmp.c:12: warning: ISO C doesn't support unnamed structs/unions
tmp.c:12: warning: declaration does not declare anything
tmp.c:13: warning: ISO C doesn't support unnamed structs/unions
tmp.c:13: warning: declaration does not declare anything
tmp.c:14: warning: struct has no members
 
T

Tom Plunket

Keith said:
No, unnamed unions are not allowed either, if I understand the term
correctly.

Given this:

struct inner_struct {
int a;
int b;
};

union inner_union {
int c;
int d;
};

struct outer {
struct inner_struct;
union inner_union;
};

both members of "struct outer" are invalid. gcc says:

tmp.c:12: warning: declaration does not declare anything
tmp.c:13: warning: declaration does not declare anything

Huh, weird. ...because the code definitely compiles and operates "as
expected" in GCC here. Maybe it's a very old version of GCC. I
remember reading about unnamed union members in some GCC documentation
many years ago. Very interesting indeed, though.

The original text that I read allowed something along these lines:

struct Foo
{
union { int i; float f; };
double d;
};

void Fn()
{
Foo f;

f.i = 6;
}

....and I just assumed that what I was seeing here was along the same
lines, because it works identically; the "unnamed thing"'s members get
pulled into the containing struct's namespace.

Alas, I see clearly now that my initial revulsion was justified. :)
-tom!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top