Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access members of a `struct' according to a variable integer in C?

Suppose I have this struct (which incidentally contain bit-fields, but you shouldn't care):

struct Element {
    unsigned int a1 : 1;
    unsigned int a2 : 1;
    ...
    unsigned int an : 1;
};

and I want to access the i'th member in a convenient way. Let's examine a retrieval solution.
I came up with this function:

int getval(struct Element *ep, int n)
{
    int val;
    switch(n) { 
         case 1: val = ep->a1; break;
         case 2: val = ep->a2; break;
         ...
         case n: val = ep->an; break;
    }
    return val;
}

But I suspect that there is a much simpler solution. Something like array accessing style, maybe.

I tried to do something like that:

 #define getval(s,n)   s.a##n

But expectedly it doesn't work.
Is there a nicer solution?

like image 449
Ori Popowski Avatar asked May 20 '09 13:05

Ori Popowski


People also ask

How would you access data members of a structure using a struct variable?

Array elements are accessed using the Subscript variable, Similarly Structure members are accessed using dot [.] operator. Structure written inside another structure is called as nesting of two structures.

How do you access struct values?

Accessing data fields in structs Although you can only initialize in the aggregrate, you can later assign values to any data fields using the dot (.) notation. To access any data field, place the name of the struct variable, then a dot (.), and then the name of the data field.

How do you access a member of a structure give an example?

The syntax for that is using a dot(.) between the object name and the member name. Example: student.name; if the members are a pointer type, then is used to access the members.

How do you access a member of a structure with its syntax?

Structure members are accessed using the structure member operator (.), also called the dot operator, between the structure name and the member name. The syntax for accessing the member of the structure is: structurevariable.


3 Answers

No, there is no simple way to do this easier. Especially for bitfields, that are hard to access indirectly through pointers (you cannot take the address of a bitfield).

You can of course simplify that function to something like this:

int getval(const struct Element *ep, int n)
{
    switch(n)
    {
      case 1: return ep->a1;
      case 2: return ep->a2;
      /* And so on ... */
    }
    return -1; /* Indicates illegal field index. */
}

And it seems obvious how the implementation can be further simplified by using a preprocessor macro that expands to the case-line, but that's just sugar.

like image 197
unwind Avatar answered Sep 20 '22 12:09

unwind


If every field in your struct is an int, then you should basically be able to say

int getval(struct Element *ep, int n)
{
    return *(((int*)ep) + n);
}

This casts the pointer to your struct to a pointer to an array if integers, then accesses the nth element of that array. Since everything in your struct seems to be an integer, this is perfectly valid. Note that this will fail horribly if you ever have a non-int member.

A more general solution would be to maintain an array of field offsets:

int offsets[3];
void initOffsets()
{
    struct Element e;
    offsets[0] = (int)&e.x - (int)&e;
    offsets[1] = (int)&e.y - (int)&e;
    offsets[2] = (int)&e.z - (int)&e;
}

int getval(struct Element *ep, int n)
{
    return *((int*)((int)ep+offsets[n]));
}

This will work in the sense that you'll be able to call getval for any of the int fields of your struct, even if you have other non-int fields in your struct, since the offsets will all be correct. However, if you tried to call getval on one of the non-int fields it would return a completely wrong value.

Of course, you could write a different function for each data type, e.g.

double getDoubleVal(struct Element *ep, int n)
{
    return *((double*)((int)ep+offsets[n]));
}

and then just call the proper function for whichever datatype you'd want. Incidentally, if you were using C++ you could say something like

template<typename T>
T getval(struct Element *ep, int n)
{
    return *((T*)((int)ep+offsets[n]));
}

and then it would work for whatever datatype you'd want.

like image 23
Eli Courtwright Avatar answered Sep 21 '22 12:09

Eli Courtwright


Unless you have specific knowledge of the underlying structure of the struct, there is no way to implement such a method in C. There are all sorts of problems that will get in the way including

  • Members of different sizes
  • Packing issues
  • Alignment issues
  • Tricks like bitfields will be problematic

You're best off implementing a method by hand for your struct which has a deep understanding of the internal members of the structure.

like image 41
JaredPar Avatar answered Sep 23 '22 12:09

JaredPar