Hey everyone. This whole topic came about because of a piece of software I was writing to bit-bang the Dallas One-Wire protocol with a standard DS18B20 temperature sensor. Because of the project, it made sense to store all the data around the sensor in a struct, so in the code we start with something like this:
...
typedef struct sensor {
int regA;
int regB;
int regC;
int regD;
} sensor_t;
...
I like organizing things like this into structs. It (usually) makes sense to declare it as a type, especially if you have multiple sensors that are the same. The problem I ran into is that in C there is no way to iterate through a struct. That is, there is no way to 'move' through the members of a struct the same way you can iterate through members of an array.
There are two different solutions for this. The first is a bit of a 'hack', and the second is a bit more elegant. They will both work, but the choice is up to you. I post this here because this problem nagged at me for a while until I finally figured out a good way to do it

So, here's the sort of 'hacked together' method:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
typedef struct test { // this method would work for non-type structs as well
int a;
int b;
int c;
int d;
int e;
int f;
} test_t;
test_t iter, *pIter = &iter;
int *temp; // this is used to iterate through the struct
int main(void) {
pIter->a = 15; // set all the members to some value
pIter->b = 16;
pIter->c = 17;
pIter->d = 18;
pIter->e = 19;
pIter->f = 20;
printf("Testing, \n %d \n %d \n %d \n %d \n %d \n %d \n", pIter->a, pIter->b, pIter->c, pIter->d, pIter->e, pIter->f);
int j;
temp = &iter.a; // point the int pointer to the first int inside the struct
for(j=0; j < 6; j++) {
*temp = j; // set the new values of the struct (this can be done many ways)
temp++; // increase the address to the next value ** see below comments
}
printf("Second go, \n %d \n %d \n %d \n %d \n %d \n %d \n", pIter->a, pIter->b, pIter->c, pIter->d, pIter->e, pIter->f);
return 0;
}
/*
* ** the temp++ line works because C pointer math will automatically increment the pointer
* by the correct size to move it to the next item. This is a function typically used
* for iterating through arrays, but it works here ONLY if your struct members are all
* the same size.
* Interestingly, setting a variable to sizeof(int) and adding this to the j variable
* results in a bizarre, different result. This is probably because of the way the C
* compiler is placing things in memory?
*/This does work, but is not particularly good use of pointers and pointer arithmetic. The above example shows why C is not a particularly 'type-safe' and memory safe language -- it certainly does give you power though!! GCC does not complain about the above code, though. (Maybe it would with -Wall, I didn't try that with this example though.)
Here is the more elegant method, which has the advantage of being able to iterate through the registers, but also call them by name when needed (the advantage of a struct!).
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#define REGS 10
typedef struct test {
int a[REGS];
int other_data;
int more_stuff;
} test_t;
enum {
registerA = 0x00,
registerB = 0x01,
registerC = 0x02,
registerD = 0x03,
registerE = 0x04
//etc
};
test_t iter, *pIter = &iter;
int main(void) {
int i, j;
pIter->a[registerA] = 15; // set all the members to some value
pIter->a[registerB] = 16;
pIter->a[registerC] = 17;
pIter->a[registerD] = 18;
pIter->a[registerE] = 19;
printf("Testing, \n");
for(i = 0; i < 5; i++) {
printf("%d \n", pIter->a[i]); // now we can iterate to print their values, as well!
}
for(j=0; j < 5; j++) {
pIter->a[j] = j; // set the new values of the struct (this can be done many ways)
}
printf("Second go, \n");
for(i = 0; i < 5; i++) {
printf("%d \n", pIter->a[i]); // now we can iterate to print their values, as well!
}
return 0;
}
Up to the first time I wrote this, I hadn't used enums much. I used to use #define for constants -- but I've heard from many sources (and it makes sense) to either use const int or an enum, as this enables the compiler to check what you're doing and look for type errors, etc, whereas #defines (which are part of the preprocessor) simply replaces verbatim whatever value you define.
In this second version, if the other chip's registers aren't in a nice linear order, you can simply create a second array with the register addresses for each register in the appropriate place (which pertains to the correct register name in the enum). This way you can iterate through the register data in the struct while also iterating through all the addresses of each register (useful if you're sending the register address before reading/writing the remote register).
I was pretty proud of this nifty little solution! The reason I posted this today is I just ran into the same problem using the Bosch BMP180 pressure sensor. In order to calculate the pressure you have to read a whole bunch of calibration constants and then use them in a bunch of equations. I wanted to put all the calibration registers into a struct, but then when I got to the part where I read them I realized it would be so much easier if I could just iterate through them in a for loop -- and then I remembered I'd solved this problem before!
There's a good chance that there is someone else out there who did a similar version before, so I'm not by any means claiming I invented this technique -- I just wanted to share it with everyone!
Hope it helps you out! If you have other methods or other interesting coding techniques, please share them as well!