Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Generically accessing members of a struct. (http://www.velocityreviews.com/forums/t685327-generically-accessing-members-of-a-struct.html)

david.chanters@googlemail.com 05-23-2009 06:45 PM

Generically accessing members of a struct.
 
Hello all,

I am curious to know some best practise techniques when traversing/
accessing struct members. At the moment I have the following
declarations:

typedef struct PayInfo
{
char *name;
char *address;
int employeeNum;
int internalId;
PayInfo *pinfo;
} PayInfo;

// Initialise an instance of PayInfo here...

Which acts as a linked list, that's fine. I then, have several
functions which look like this:

char *GetEmpname(int number)
{
PayInfo pi;
pi = MyInitializedPayInfo->next;

while(pi != NULL && pi->employeeNum != number)
pi = pi->next;

if (pi != NULL)
return pi->name;

return NULL;
}

That's just one example, I also have:

char *GetAddress(int number);
int GetInternalId(int number);

Which do the exact same thing as GetEmpname() but returns different
data.

My thinking is that this is inefficient, especially if/when the struct
has more members added to it. My thoughts are to have a enum which is
passed around, so I could say something like:

GetGenericMember(PayInfo *pi, enum flags)

Where this enum would list which attribute I want returned. Is this a
good idea? Are there some other way of doing this I am not thinking
about, or am I just missing the point, and instead should just have
one function per data member I want returned?

Suggestions welcome, and thanks in advance.

David.

Eric Sosman 05-23-2009 07:05 PM

Re: Generically accessing members of a struct.
 
david.chanters@googlemail.com wrote:
> Hello all,
>
> I am curious to know some best practise techniques when traversing/
> accessing struct members. At the moment I have the following
> declarations:
>
> typedef struct PayInfo
> {
> char *name;
> char *address;
> int employeeNum;
> int internalId;
> PayInfo *pinfo;


This looks bogus. Did you mean `struct PayInfo *next;'?

> } PayInfo;
>
> // Initialise an instance of PayInfo here...
>
> Which acts as a linked list, that's fine. I then, have several
> functions which look like this:
>
> char *GetEmpname(int number)
> {
> PayInfo pi;
> pi = MyInitializedPayInfo->next;
>
> while(pi != NULL && pi->employeeNum != number)
> pi = pi->next;


No `next' field in the struct as you've shown it ...

> if (pi != NULL)
> return pi->name;
>
> return NULL;
> }
>
> That's just one example, I also have:
>
> char *GetAddress(int number);
> int GetInternalId(int number);
>
> Which do the exact same thing as GetEmpname() but returns different
> data.
>
> My thinking is that this is inefficient, especially if/when the struct
> has more members added to it. My thoughts are to have a enum which is
> passed around, so I could say something like:
>
> GetGenericMember(PayInfo *pi, enum flags)
>
> Where this enum would list which attribute I want returned. Is this a
> good idea? Are there some other way of doing this I am not thinking
> about, or am I just missing the point, and instead should just have
> one function per data member I want returned?


You should probably write a function that locates
the whole struct rather than just one field:

PayInfo *GetEmpPayInfo(int number) {
PayInfo *pi;
pi = MyInitializedPayInfo->next;
for ( ; pi != NULL; pi = pi->next) {
if (pi->employeeNum == number)
break;
}
return pi;
}

Now you can write all the "get attribute" functions as
simple wrappers:

char *GetEmpName(int number) {
PayInfo pi = GetEmpPayInfo(number);
return pi == NULL ? NULL : pi->name;
}

.... or if you prefer you can call GetEmpPayInfo() directly
from your main-line code.

The enum approach can be viable, but one difficulty
it runs into is that a C function can return only one data
type. You can't have a function that sometimes returns an
`int' and sometimes returns a `char*'. You could return a
union that can hold any of these types, but then the caller
would have to know which of the union's members to look at.
It *does* know that, of course (if it asked for the name,
it's not going to expect to get a `double' back), but it
seems to me a trifle safer and certainly more straightforward
to use other means: Call GetEmpName(), or call GetEmpPayInfo()
and refer to the element of interest.

--
Eric Sosman
esosman@ieee-dot-org.invalid

BartC 05-23-2009 07:19 PM

Re: Generically accessing members of a struct.
 

<david.chanters@googlemail.com> wrote in message
news:fccd8b77-5c95-4a14-80fb-950dfb1204d5@21g2000vbk.googlegroups.com...
> Hello all,
>
> I am curious to know some best practise techniques when traversing/
> accessing struct members. At the moment I have the following
> declarations:
>
> typedef struct PayInfo
> {

....
> } PayInfo;


> char *GetEmpname(int number)
> {
> PayInfo pi;
> pi = MyInitializedPayInfo->next;
>
> while(pi != NULL && pi->employeeNum != number)
> pi = pi->next;
> if (pi != NULL)
> return pi->name;
> return NULL;
> }
>
> That's just one example, I also have:
>
> char *GetAddress(int number);
> int GetInternalId(int number);
>
> Which do the exact same thing as GetEmpname() but returns different
> data.
>
> My thinking is that this is inefficient, especially if/when the struct
> has more members added to it. My thoughts are to have a enum which is
> passed around, so I could say something like:
>
> GetGenericMember(PayInfo *pi, enum flags)
>
> Where this enum would list which attribute I want returned. Is this a
> good idea? Are there some other way of doing this I am not thinking
> about, or am I just missing the point, and instead should just have
> one function per data member I want returned?


Somehow creating a separate function to access a field, or to select a field
using an index, doesn't sound right.

Normally you'd use "." or "->" to select fields, so you really need a
function to select the /entry/ using the employee number or whichever key
you wish to use:

x = Findempnum(1199)->name;
Findempnum(1200)->address = ".....";

This allows you to read or write any field. And to select on another key
just use a different function to Findempnum(). Also adding/removing fields
requires less maintenance.

--
Bart


gw7rib@aol.com 05-24-2009 06:59 PM

Re: Generically accessing members of a struct.
 
On 23 May, 20:05, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> david.chant...@googlemail.com wrote:
> > Hello all,

>
> > I am curious to know some best practise techniques when traversing/
> > accessing struct members. *At the moment I have the following
> > declarations:

>
> > typedef struct PayInfo
> > {
> > * * char *name;
> > * * char *address;
> > * * int employeeNum;
> > * * int internalId;
> > * * PayInfo *pinfo;

>
> * * *This looks bogus. *Did you mean `struct PayInfo *next;'?
>
> > } PayInfo;

>
> > // Initialise an instance of PayInfo here...

>
> > Which acts as a linked list, that's fine. *I then, have several
> > functions which look like this:

>
> > char *GetEmpname(int number)
> > {
> > * * PayInfo pi;
> > * * pi = MyInitializedPayInfo->next;

>
> > * * while(pi != NULL && pi->employeeNum != number)
> > * * * * pi = pi->next;

>
> * * *No `next' field in the struct as you've shown it ...
>
>
>
>
>
> > * * if (pi != NULL)
> > * * * * return pi->name;

>
> > * * return NULL;
> > }

>
> > That's just one example, I also have:

>
> > char *GetAddress(int number);
> > int GetInternalId(int number);

>
> > Which do the exact same thing as GetEmpname() but returns different
> > data.

>
> > My thinking is that this is inefficient, especially if/when the struct
> > has more members added to it. *My thoughts are to have a enum which is
> > passed around, so I could say something like:

>
> > GetGenericMember(PayInfo *pi, enum flags)

>
> > Where this enum would list which attribute I want returned. *Is this a
> > good idea? *Are there some other way of doing this I am not thinking
> > about, or am I just missing the point, and instead should just have
> > one function per data member I want returned?

>
> * * *You should probably write a function that locates
> the whole struct rather than just one field:
>
> * * * * PayInfo *GetEmpPayInfo(int number) {
> * * * * * * PayInfo *pi;
> * * * * * * pi = MyInitializedPayInfo->next;
> * * * * * * for ( *; *pi != NULL; *pi = pi->next) {
> * * * * * * * * if (pi->employeeNum == number)
> * * * * * * * * * * break;
> * * * * * * }
> * * * * * * return pi;
> * * * * }
>
> Now you can write all the "get attribute" functions as
> simple wrappers:
>
> * * * * char *GetEmpName(int number) {
> * * * * * * PayInfo pi = GetEmpPayInfo(number);
> * * * * * * return pi == NULL ? NULL : pi->name;
> * * * * }
>
> ... or if you prefer you can call GetEmpPayInfo() directly
> from your main-line code.
>
> * * *The enum approach can be viable, but one difficulty
> it runs into is that a C function can return only one data
> type. *You can't have a function that sometimes returns an
> `int' and sometimes returns a `char*'. *You could return a
> union that can hold any of these types, but then the caller
> would have to know which of the union's members to look at.
> It *does* know that, of course (if it asked for the name,
> it's not going to expect to get a `double' back), but it
> seems to me a trifle safer and certainly more straightforward
> to use other means: Call GetEmpName(), or call GetEmpPayInfo()
> and refer to the element of interest.


I'd endorse what Eric says. It seems a bit too abstract to be trying
to access each member by the same function - particularly as you are
not going to be doing the same sort of things with, say, name, as you
are going to be doing with employeeNum.

It's good that you are able to think abstractly and that you are
considering this sort of issue. But I think in this particular case
your solution is more abstract than is justified.

Paul.


All times are GMT. The time now is 02:14 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.