J B
J B

Reputation: 137

Storing values directly into C struct with an array index

I can read out all the variable values of a generic C struct (assuming all same variable types) using

struct whichstruct{
  float firstVar;
  float ...
  ...
};
whichstruct whichStruct;

void printParams(structType *whichStruct) {
  // Print out all values of a struct.
  float *startVar = &(whichStruct->firstVar);
  int numElements = sizeof(*whichStruct) / sizeof(startVar);
  for (int i = 0; i < numElements; ++i)
    printf("%d: %f\r\n", i, startVar[i]);
}

How can I store values equivalently, if I want to store to say member variable #10? This following does not work at the whichStruct[i] line, obviously, since it's not an array. But you get the idea...

void setParams(structType *whichStruct, const int whichVar, const float val) {
  // whichVar is the struct's member variable to access (2nd, 3rd, etc)
  float *startVar = &(whichStruct->firstVar);
  int numElements = sizeof(*whichStruct) / sizeof(startVar);
  int index = sizeof(startVar) * whichVar; // How many bytes into the struct?
  whichset[index] = val; // <-- trying to poke the value at the struct's correct byte address
  printf("#%d = %f\r\n", whichVar, whichStruct[index]);
}

How can I store directly by indexing into the struct? I want to write to the address directly, it seems, using something like

int* address = whichStruct + index; 
*address = val;

Upvotes: 1

Views: 357

Answers (3)

luser droog
luser droog

Reputation: 19494

A more elaborate version of dasblinkenlight's alternate suggestion is one of my favorite things to do. You can use an X-Macro to describe the table with symbolic names for each entry. The X-Macro lets you peel-off the symbols into an enum and then use the other data to initialize an array. Edits to the table maintain the symbolic association (unless, of course, you screw it up somehow, always a possibility).

#define FLOATTAB(_) \
    _(FirstVar, 1.0) \
    _(SecondVar, 2.0) \
    /* end FLOATTAB */
#define FLOATTAB_NAME(a,b) a,
enum { FLOATTAB(FLOATTAB_NAME) };
#define FLOATTAB_DATA(a,b) b,
float ftab[] = { FLOATTAB(FLOATTAB_DATA) };

Then you can access a data member with the symbolic name.

ftab[FirstVar];

which is almost as clear as fstruct.FirstVar;, but puts everything in an array, and FirstVar is now an index, a small integer which can be stored in a variable.

Upvotes: 0

b4hand
b4hand

Reputation: 9770

You can use the offsetof macro to find the byte offset into the struct. Then you just do some pointer arithmetic to access the field.

*((float *) (((void *)&whichStruct) + offsetof(whichstruct, firstVar))) = val;

Upvotes: 3

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726569

Since all variables are of the same type, the fields are going to be stored next to each other, with no gaps between them. Therefore, you can index into your struct like this:

void setParams(structType *whichStruct, const int whichVar, const float val) {
    float *startVar = &(whichStruct->firstVar);
    startVar[whichVar] = val;
    printf("#%d = %f\r\n", whichVar, whichStruct[index]);
}

Another alternative would be to replace the individual fields of your struct with an array of equivalent size, and provide a #define-d constant for each field name. This way your code would reflect the same meaning, and provide a way to access array elements in a natural way.

Upvotes: 2

Related Questions