Connecting Tech Pros Worldwide Help | Site Map

Returning common field of multiple structs

Guillaume Dargaud
Guest
 
Posts: n/a
#1: Nov 21 '08
Hello all,
I wonder if there's a way to obtain a given field from different structs.
Something like this:

struct sDigital {
char Label[255];
int Something;
} tDigital;

struct sAnalog {
double SomethingElse;
char Label[255];
} tAnalog;

char *GetLabel(void* DigOrAnal) {
return DigOrAnal->Label;
}

I know that doesn't work and I have to add a type variable indicator and a
slew of 'if' tests. But I wonder if there are some simplifying tricks.
--
Guillaume Dargaud
http://www.gdargaud.net/


Eric Sosman
Guest
 
Posts: n/a
#2: Nov 21 '08

re: Returning common field of multiple structs


Guillaume Dargaud wrote:
Quote:
Hello all,
I wonder if there's a way to obtain a given field from different structs.
Something like this:
>
struct sDigital {
char Label[255];
int Something;
} tDigital;
>
struct sAnalog {
double SomethingElse;
char Label[255];
} tAnalog;
>
char *GetLabel(void* DigOrAnal) {
return DigOrAnal->Label;
}
>
I know that doesn't work and I have to add a type variable indicator and a
slew of 'if' tests. But I wonder if there are some simplifying tricks.
Not that I can think of. If you're free to rearrange the
structs so you can put Label first, it's easily solved -- but
as shown, I think you're out of luck. No "MOVE CORRESPONDING"
in C, I'm afraid.

--
Eric Sosman
esosman@ieee-dot-org.invalid
Chris Dollin
Guest
 
Posts: n/a
#3: Nov 21 '08

re: Returning common field of multiple structs


Guillaume Dargaud wrote:
Quote:
Hello all,
I wonder if there's a way to obtain a given field from different structs.
Something like this:
>
struct sDigital {
char Label[255];
int Something;
} tDigital;
>
struct sAnalog {
double SomethingElse;
char Label[255];
} tAnalog;
>
char *GetLabel(void* DigOrAnal) {
return DigOrAnal->Label;
}
>
I know that doesn't work and I have to add a type variable indicator and a
slew of 'if' tests. But I wonder if there are some simplifying tricks.
Yes; the simplifying trick is not to fall into this trap. If you find that
it's happening, /stop/ and think about what it implies about your design.

The most obvious fix is to use a struct with a Label field (which might
usefully be `char*`, not `char[]`, depending) and a union of sDigital
and sAnalog. For that you might want your type indicator and if-stew.
But at least you've got rid of one tripwire.

(I say "stew" not "slew" in homage to the signature.)

--
"It is seldom good news." ~Crystal Ball~, /The Tough Guide to Fantasyland/

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

John Bode
Guest
 
Posts: n/a
#4: Nov 21 '08

re: Returning common field of multiple structs


On Nov 21, 6:13*am, "Guillaume Dargaud"
<use_the_form_on_my_contact_p...@www.gdargaud.netw rote:
Quote:
Hello all,
I wonder if there's a way to obtain a given field from different structs.
Something like this:
>
struct sDigital {
*char Label[255];
*int Something;
>
} tDigital;
>
struct sAnalog {
*double SomethingElse;
*char Label[255];
>
} tAnalog;
>
char *GetLabel(void* DigOrAnal) {
* * return DigOrAnal->Label;
>
}
>
I know that doesn't work and I have to add a type variable indicator and a
slew of 'if' tests. But I wonder if there are some simplifying tricks.
--
Guillaume Dargaudhttp://www.gdargaud.net/
Chris Dollin's suggestion is the right one; redesign your types so
that you have a single struct type with variant members for analog and
digital:

typedef struct sComm
{
char Label[255];
union {
tdigital digitalStuff;
tanalog analogStuff;
} digitalOrAnalog;
} tComm;

Having said that, here's one trick I've used in the past, and I think
it's applicable generally (but don't take my word for it). The
address of the first member of a struct object is the same as the
address of the struct object itself. You could rearrange your struct
definitions so that Label is the first member of both:

typedef struct sDigital
{
char Label[255];
...
} tDigital;

typedef struct sAnalog
{
char Label[255];
...
} tAnalog;

That way, a pointer to the struct can easily be cast into a pointer to
the Label buffer:

tDigital d;
char *dlabel = (char *) &d; // dlabel now points to d.Label
tAnalog a;
char *alabel = (char *) &a; // alabel now points to a.Label

Obviously, that's a bit ugly and non-intuitive, which is why you
should go with Chris' suggestion.
Andrey Tarasevich
Guest
 
Posts: n/a
#5: Nov 21 '08

re: Returning common field of multiple structs


Guillaume Dargaud wrote:
Quote:
I wonder if there's a way to obtain a given field from different structs.
Something like this:
>
struct sDigital {
char Label[255];
int Something;
} tDigital;
>
struct sAnalog {
double SomethingElse;
char Label[255];
} tAnalog;
>
char *GetLabel(void* DigOrAnal) {
return DigOrAnal->Label;
}
>
I know that doesn't work and I have to add a type variable indicator and a
slew of 'if' tests. But I wonder if there are some simplifying tricks.
Give the above type definitions, there are no "simplifying tricks"
besides a simple macro

#define GetLabel(DigOrAnal) ((DigOrAnal)->Label)

If you can change the types, the alternative approach would be to
simulate a C++-like class hierarchy

struct sLabeled {
char Label[255];
};

struct sDigital {
sLabeled Label;
int Something;
} tDigital;

STATIC_ASSERT(offsetof(sDigital, Label) == 0);

struct sAnalog {
sLabeled Label;
double SomethingElse;
} tAnalog;

STATIC_ASSERT(offsetof(sAnalog, Label) == 0);

char *GetLabel(void* DigOrAnal) {
/* assert(<make sure it is really safe>); */
return ((sLabeled*) DigOrAnal)->Label;
}

...
sDigital d;
sAnalog a;
...
char *dl = GetLabel(&d);
char *al = GetLabel(&a);

Of course, it is a good idea to put a bunch of safeguard into this
dangerous code, which will perform a run-time check of the data passed
to 'GetLabel' at least in "debug" configuration of the program (like add
a signature to 'sLabeled').

--
Best regards,
Andrey Tarasevich
Closed Thread


Similar C / C++ bytes