Iterating Through Variable Names

D

digital.pardoe

Hi,

I have had a little programming experience with C but not enough to
accomplish what I am trying to do. Nor have I been able to find any
references on the internet regarding what I am trying to do.

Basically, I have a structure, which I am unable to change, inside
this structure are fields of an integer type that have the names: F0,
F1, F2, F3, F4, F5.

All I want to be able to to is iterate through them is something along
the lines of this pseudocode;

for(N, N == 5, N++) {
STRUCTURE.F{N} = SOME_VAL;
}

I think I may need to utilize an array or hash but I'm really not
sure.

Basically I want to append N to the variable name. Is this possible,
is there some other way of doing it?

Thanks,
Alex
 
A

Antoninus Twink

Basically, I have a structure, which I am unable to change, inside
this structure are fields of an integer type that have the names: F0,
F1, F2, F3, F4, F5.

All I want to be able to to is iterate through them is something along
the lines of this pseudocode;

for(N, N == 5, N++) {
STRUCTURE.F{N} = SOME_VAL;
}

If F0,...,F5 are successive fields in the struct, then it's very likely
that you can do something like

int *ip = &structure.F0;
for(i=0; i<=5; i++, ip++)
/* do stuff */

Otherwise, you could use offsetof to build a table of the offsets of the
different fields, and then do something very much like indirect
addressing.
 
D

David Resnick

If F0,...,F5 are successive fields in the struct, then it's very likely
that you can do something like

int *ip = &structure.F0;
for(i=0; i<=5; i++, ip++)
/* do stuff */

This is not very good code IMHO. Not written with an eye to being
maintainable, hopefully wouldn't pass a code review. Forgetting the
padding issue (seems unlikely to me that padding will between ints, I
assume you mean that by your "likely" comment, though an assert could
be added to test this), lying to the compiler means that it won't
notice changes in the struct. This code will continue to compile just
fine as long as something named F0 remains if you, for example
eliminate F5
insert something between F2 and F3
reorder the fields, putting F0 last
etc

Resulting in some irritating memory overwrites or uninitialized memory
that could be a bit of a pain to debug. Yeah, maybe nobody will ever
reorder or otherwise munge this struct, but too many such assumptions
that nobody will ever do a variety of unlikely things means one will
happen somewhere anyway...
Otherwise, you could use offsetof to build a table of the offsets of the
different fields, and then do something very much like indirect
addressing.

Seems a more maintainable choice to me assuming it needs doing at
all. I assume that the OP actually has a good reason for this, as
opposed to the simpler and very clear:
STRUCTURE.F0 = SOME_VAL;
STRUCTURE.F1 = SOME_VAL;
....
STRUCTURE.F5 = SOME_VAL;

-David
 
R

Richard Tobin

Basically, I have a structure, which I am unable to change, inside
this structure are fields of an integer type that have the names: F0,
F1, F2, F3, F4, F5.

All I want to be able to to is iterate through them is something along
the lines of this pseudocode;

for(N, N == 5, N++) {
STRUCTURE.F{N} = SOME_VAL;
}

You can build an array containing the offsets of the fields,
and then do a little pointer arithmetic:

#include <stdio.h>
#include <stddef.h>

struct foo {
int f0, f1, f2, f3, f4, f5;
};

size_t foo_f_offset[6] = {
offsetof(struct foo, f0),
offsetof(struct foo, f1),
offsetof(struct foo, f2),
offsetof(struct foo, f3),
offsetof(struct foo, f4),
offsetof(struct foo, f5)
};

int main(void)
{
int i;
struct foo myfoo;

for(i=0; i<=5; i++)
*(int *)((char *)&myfoo + foo_f_offset) = i*i;

printf("myfoo.f4 = %d\n", myfoo.f4);

return 0;
}

-- Richard
 
D

digital.pardoe

If F0,...,F5 are successive fields in the struct, then it's very likely
that you can do something like

int *ip = &structure.F0;
for(i=0; i<=5; i++, ip++)
  /* do stuff */

Otherwise, you could use offsetof to build a table of the offsets of the
different fields, and then do something very much like indirect
addressing.

Hi,

Thanks for your help.

Alex.
 
D

digital.pardoe

Hi,

Right, basically I think I've been really stupid in not reading the
documentation (what there is of it) properly and probably wasted your
time (although your code has gone into my code library because I can
see myself using it somewhere).

I think I need a better explanation of the problem as I am now
struggling to understand it myself.

I am actually programming a PIC chip using C, P16F627 to be precise
and I have plenty of information and have successfully programmed it
in assembly but I want to make my programming a little easier and I am
trying to program it in C, the documentation for C however is
virtually non existent and I had to work out some things by 'reverse
engineering' the assembly into C.

I think, what I originally stated as a struct is actually a bit field.
I will explain how it works however and allow you to make up your
mind.

PORTB <- what I originally thought was a structure, allows me to use
the output pins of the chip of which there are 6. In assembly the
assignments to turn the outputs on and off in sequence are as follows;

PORTB B'00000001'
PORTB B'00000010'
PORTB B'00000100'
PORTB B'00001000'
PORTB B'00010000'
PORTB B'00100000'

I can do this in C by performing the following;

PORTB = 1
PORTB = 2
PORTB = 4
PORTB = 8
PORTB = 16
PORTB = 32

If I assign products of this then I can get multiple outputs to turn
on;

PORTB = 63 // Turns all outputs on.

I mechanism is also provided to access and set each individual output;

PORTB.F0 = 1 // Turn output 1 on.
PORTB.F0 = 1 // Turn output 1 off.
PORTB.F1 = 1 // Turn output 2 on.
PORTB.F1 = 1 // Turn output 2 off.

This means that I can use;

PORTB.F0 = ~PORTB.F0

To toggle the output on or off.

Essentially what I am trying to do as part of my first very basic
program is turn the outputs on in sequence, then off in sequence. I
can do this;

void main() {
while(1) {
PORTB.F0 = ~PORTB.F0;
Delay_ms(100);
PORTB.F1 = ~PORTB.F1;
Delay_ms(100);
PORTB.F2 = ~PORTB.F2;
Delay_ms(100);
PORTB.F3 = ~PORTB.F3;
Delay_ms(100);
PORTB.F4 = ~PORTB.F4;
Delay_ms(100);
PORTB.F5 = ~PORTB.F5;
Delay_ms(100);
}
}

I suppose it's a re-factoring issue more than anything but I can see a
lot of code repetition above that I would prefer to shorten as per my
original post.

Obviously, the number of output pins doesn't change and I would prefer
to use the PORTB.Fx method rather than work out all the maths to have
to use the PORTB = x method of setting to outputs.

Hope I haven't annoyed people to much with my initial stupidity. If
people think it would be more appropriate I will move this topic to a
PIC mailing list.

Thanks & apologies,
Alex
 
B

Bartc

I am actually programming a PIC chip using C, P16F627 to be precise
I think, what I originally stated as a struct is actually a bit field.
I will explain how it works however and allow you to make up your
mind.
PORTB = 63 // Turns all outputs on.
Essentially what I am trying to do as part of my first very basic
program is turn the outputs on in sequence, then off in sequence. I
can do this;

void main() {
while(1) {
PORTB.F0 = ~PORTB.F0;
Delay_ms(100);
PORTB.F1 = ~PORTB.F1;
Delay_ms(100);
PORTB.F2 = ~PORTB.F2;
Delay_ms(100);
PORTB.F3 = ~PORTB.F3;
Delay_ms(100);
PORTB.F4 = ~PORTB.F4;
Delay_ms(100);
PORTB.F5 = ~PORTB.F5;
Delay_ms(100);
}
}

I suppose it's a re-factoring issue more than anything but I can see a
lot of code repetition above that I would prefer to shorten as per my
original post.

Obviously, the number of output pins doesn't change and I would prefer
to use the PORTB.Fx method rather than work out all the maths to have
to use the PORTB = x method of setting to outputs.

There's little maths involved. To turn on the first bit write 1. To turn on
the next bit, write 3:

bits=1;
for (i=0; i<6; ++i) {
PORTB = bits;
bits = (bits<<1) |1;
delay...
}

bits=63;
for (i=0; i<6; ++i) {
PORTB = bits;
bits = (bits<<1); /* propagate 0 into lower bits */
delay...
}

I haven't tested this but I think it's on the right lines. If you really
want to use F0 to F5, you can write a couple of functions getbit(n) and
setbit(n,x), each of which uses a switch statement to access F0 to F5, and
use those instead, if you don't like bit-fiddling.
 
D

digital.pardoe

There's little maths involved. To turn on the first bit write 1. To turn on
the next bit, write 3:

bits=1;
for (i=0; i<6; ++i) {
 PORTB = bits;
 bits = (bits<<1) |1;
 delay...
 }

bits=63;
for (i=0; i<6; ++i) {
 PORTB = bits;
 bits = (bits<<1); /* propagate 0 into lower bits */
 delay...
 }

I haven't tested this but I think it's on the right lines. If you really
want to use F0 to F5, you can write a couple of functions getbit(n) and
setbit(n,x), each of which uses a switch statement to access F0 to F5, and
use those instead, if you don't like bit-fiddling.

The code works perfectly, just reading through my C book to better
understand what it does then I'll see if I can write some code that
produces another sequence.

Thanks,
Alex.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top