tokens concat

C

c.prog.fan

Hi
Please consider this code :

#define CONCAT(token,digit) token##digit

enum EN {
elem ;
} ;

struct ST {
int elem1;
int elem2;
} ;

void func (struct ST *st){
unsigned d;
for ( d=1 ; d <= 2 ; d++ )
if ( st->CONCAT(elem,d) == 0 )
st->CONCAT(elem,d) = 1;
return ;
} ;


As you may infer from the code the purpose is to change the value of
first 0-valued element of structure to 1.
I wonder if this could be done this way.Here compiler says elemd is
not a member of struct.I tried other things like st->CONCAT(elem,*&d)
but it did not work too.Also note that EN and ST can have several
members in same style but also note that ST can be a compound
structure.
Hints are appreciated on what to do here and also other methods to do
this in general.

ps. I assume this may work:

void func2 ( struct ST *st ){
unsigned d;
if ( st->elem1 == 0)
st->elem1=1;
else if ( st->elem2 == 0)
st->elem2 = 1;
else {} ;

return ;
};
 
V

viza

Hi
Please consider this code :

#define CONCAT(token,digit) token##digit

for ( d=1 ; d <= 2 ; d++ )
if ( st->CONCAT(elem,d) == 0 )

Preprocessing occurs before compilation and execution, so the
preprocessor has no idea that d represents a number. To the preprocessor
it is just a token "d", which it pastes to "elem", as "elemd".

If you want to to this you should use an array not struct members.

If you are forced to use struct members, then you need to make an array
of the offsetof the members and index that with d.

untested:

size_t offset_array[ N_MEMBERS ]= {
offsetof( struct foo, mem0 ),
offsetof( struct foo, mem1 ),
offsetof( struct foo, mem2 ),
etc.
};

for( d=1; d < N_MEMBERS; d++ )
if( 0 == *(int*)((st)+offset_array[d]) )
etc.
 
C

c.prog.fan

Preprocessing occurs before compilation and execution, so the
preprocessor has no idea that d represents a number. To the preprocessor
it is just a token "d", which it pastes to "elem", as "elemd".

If you want to to this you should use an array not struct members.

If you are forced to use struct members, then you need to make an array
of the offsetof the members and index that with d.

untested:

size_t offset_array[ N_MEMBERS ]= {
offsetof( struct foo, mem0 ),
offsetof( struct foo, mem1 ),
offsetof( struct foo, mem2 ),
etc.
};

for( d=1; d < N_MEMBERS; d++ )
if( 0 == *(int*)((st)+offset_array[d]) )
etc.

Thanks I may use a one by one check.
 
S

Sri Harsha Dandibhotla

Hi
Please consider this code :

#define CONCAT(token,digit) token##digit

enum EN {
        elem ;

} ;

struct ST {
        int elem1;
        int elem2;

} ;

void func (struct ST *st){
        unsigned d;
        for ( d=1 ; d <= 2 ; d++ )
                if ( st->CONCAT(elem,d) == 0 )
                        st->CONCAT(elem,d) = 1;
        return ;

} ;

As you may infer from the code the purpose is to change the value of
first 0-valued element of structure to 1.
I wonder if this could be done this way.Here compiler says elemd is
not a member of struct.I tried other things like st->CONCAT(elem,*&d)
but it did not work too.Also note that EN and ST can have several
members in same style but also note that ST can be a compound
structure.
Hints are appreciated on what to do here and also other methods to do
this in general.

ps. I assume this may work:

void func2 ( struct ST *st ){
        unsigned d;
        if ( st->elem1 == 0)
                st->elem1=1;
        else if ( st->elem2 == 0)
                st->elem2 = 1;
        else {} ;

        return ;

};

The best method would of course be to use an array instead. But since
you mentioned in another reply of yours that the struct has been in
place since before, you could do this :

void func (struct ST *st)
{
unsigned d;
int *p = (int *)st;
for (d = 0; d <= 1; d++) {
if (*(p + d) == 0) {
*(p + d) = 1;
return ;
}
}
}

You could do something like the above code if the struct contains all
int's. I think that if the struct contains only members of type int,
this should work across all platforms as there is no danger of struct
padding.
 
C

c.prog.fan

The best method would of course be to use an array instead. But since
you mentioned in another reply of yours that the struct has been in
place since before, you could do this :

void func (struct ST *st)
{
unsigned d;
int *p = (int *)st;
for (d = 0; d <= 1; d++) {
if (*(p + d) == 0) {
*(p + d) = 1;
return ;
}
}
}

You could do something like the above code if the struct contains all
int's. I think that if the struct contains only members of type int,
this should work across all platforms as there is no danger of struct
padding.

Do you mean that excluding padding ; in this case st should place all
its elements in memory like an array ? What does standard say about
it ?

Thanks.
 
S

Sri Harsha Dandibhotla

Do you mean that excluding padding ; in this case st should place all
its elements in memory like an array ? What does standard say about
it ?

Thanks.

Yes, if all members were of type int, there would be no padding
between the members so the elements would be like in an array.
 
E

Eric Sosman

Sri said:
[...]
The best method would of course be to use an array instead. But since
you mentioned in another reply of yours that the struct has been in
place since before, you could do this :

void func (struct ST *st)
{
unsigned d;
int *p = (int *)st;
for (d = 0; d <= 1; d++) {
if (*(p + d) == 0) {
*(p + d) = 1;
return ;
}
}
}

You could do something like the above code if the struct contains all
int's. I think that if the struct contains only members of type int,
this should work across all platforms as there is no danger of struct
padding.

For "no danger" read "little danger." Nobody seems to
have heard of a compiler that would insert padding between
two identically-typed struct elements, but the language
definition does not forbid it. For a completely foolproof
approach, you could use an array of offsets as suggested
elsethread by viza:
> size_t offset_array[ N_MEMBERS ]= {
> offsetof( struct foo, mem0 ),
> offsetof( struct foo, mem1 ),
> offsetof( struct foo, mem2 ),
> etc.
> };
>
> for( d=1; d < N_MEMBERS; d++ )
> if( 0 == *(int*)((st)+offset_array[d]) )
> etc.

.... but with the addition of one necessary cast:

if ( 0 == *(int*)((char*)st + offset_array[d]) )

.... because the offsets are measured in units of `char', not
in units of `struct ST'.
 
B

Ben Bacarisse

Sri Harsha Dandibhotla said:
Yes, if all members were of type int, there would be no padding
between the members so the elements would be like in an array.

That is a bit too dogmatic. It is likely but not certain that there
will be no padding.

If the OP decides to take this risk, I suggest testing the assumption
first. Since a compiler may add padding after the last element of a
struct simply testing that sizeof(struct ST) == sizeof(int[2]) is too
strict. You need to test that the last element is at the expected
offset:

offsetof(struct ST, elem2) == sizeof(int[1])

(Obviously, adjust the numbers according to the number of elements you
really have.) You can use one of the many "compile-time assertion"
tricks to ensure that the code will compile only when this test is
true.
 
C

c.prog.fan

Ben said:
Sri Harsha Dandibhotla said:
Yes, if all members were of type int, there would be no padding
between the members so the elements would be like in an array.

That is a bit too dogmatic. It is likely but not certain that there
will be no padding.

If the OP decides to take this risk, I suggest testing the assumption
first. Since a compiler may add padding after the last element of a
struct simply testing that sizeof(struct ST) == sizeof(int[2]) is too
strict. You need to test that the last element is at the expected
offset:

offsetof(struct ST, elem2) == sizeof(int[1])

(Obviously, adjust the numbers according to the number of elements you
really have.) You can use one of the many "compile-time assertion"
tricks to ensure that the code will compile only when this test is
true.

Thanks
Still as you said this method may not work in some circumstances so
adding compile time tests may inform one but what to do if that
happens ? So I used the method mentioned in the previous thread .

ps : It would be nice if these threads could be merged somehow.
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top