Pergunta

Good Morning All,

I'm trying to reduce a function that's very repetitive, but each "repetition" has two structs with struct A.element1 setting struct B.element1. At the moment I have myFunction() with about twelve different reqFunction() calls to set B to A. Basically what I have now is:

void myFunction( structB *B )
{
    structA  A;

    if( reqGetFunction( GLOBAL_IN_1, ( void *)&A, SIZE ) != 0 )
    {
        A.element3 = -1;
        printf( "element3 failed\n" );
    }
    B->element7 = A.element3;   // A is gotten when regGetFunction() is called
    .
    .
    .
    if( reqGetFunction( GLOBAL_IN_12, ( void *)&A, SIZE ) != 0 )
    {
        A.element14 = -1;
        printf( "element14 failed\n" );
    }
    B->element18 = A.element14;
}

reqGetFunction() can't be changed. I have a static global array for other functions that would loop through GLOBAL_IN, and I could make structA A a static global.

I want to have something like myFunctionSingle() that will do one block, and myFunctionAll() that will have a for loop to cycle through the GLOBAL_IN array as well as the elements of struct's A and B and input them to myFunctionSingle().

So I guess my real question is how could I cycle through the elements of the structs as I can with an array, because everything there (like the structs' setups and reqGetFunction) are set in stone. I've tried a few things and searched around, but am currently stumped. I'm honestly not sure if this is possible or even worth it. Thank you in advance for your input!

Foi útil?

Solução

Your function calls differ by 1)GLOBAL_IN_XX values 2)A.elementxx that you modify. 3)B.elementxx that you modify What you need to do is to create a struct containing a value for GLOBAL_IN_XX a pointers to A.element and B.element, whatever type they are, for example:

struct call_parms
{
int global_parm;
int* a_ptr;
int* b_ptr;
};

Then, you need to create an array of those and initialize it accordingly, for example:

struct call_parms callParmsArray[MAX_CALLS]= {{GLOBAL_IN_1,&A.element3,&(B->element5)}, ... };

Then, just iterate over array and call your reqGetFunction with the parameters specified in each array element,something along the lines of:

for(int i = 0; i<MAX_CALLS;i++)
{
reqGetFunction( callParmsArray[i].global_parm, callParmsArray[i].element_ptr, SIZE );
}

You may also want factor a pointer to B->element in the struct and deal with it accordingly, as it is also repetitive. This will likely involve creating a wrapper around reqGetFunction() which will also deal with B and such:

struct call_parms
    {
    int global_parm;
    int* a_ptr;
    int* b_ptr;
    };

bool myReqFn(struct call_parms* parm)
{
bool res;
if( res = reqGetFunction( parm->global_parm, ( void *)&A, SIZE ) != 0 )
    {
        *(parm->a_ptr) = -1;
        printf( "element %d failed\n",parm->global_parm );
    }

*(parm->b_ptr) = *(parm->a_ptr);
return res;
}

for(int i = 0; i<MAX_CALLS;i++)
{
myReqFn( &callParmsArray[i]);
}

The rest is left as an exercise to the reader, as they say...

Outras dicas

One way to cycle through a struct that I know of is to use pointer math. I'm not sure what kind of datatype your struct members are, but if you have a concurrent set of identical datatypes numbered from j to k, your code would look something like this:

(_datatype_)*a = &(A.elementj);
(_datatype_)*b = &(B.elementj);

int i;
for (i = j; i < k; i++)
{
    *(b + ((_sizeofdatatype) * (i - j)) = *(a + ((_sizeofdatatype) * (i - j));
}

EDIT: This is also, of course, assuming that you want to duplicate each pair of corresponding elements in order, but you can probably tweak it around to get the desired effect.

EDIT: This also assumes you allocate your entire struct (including variables) at the same time, so be careful.

Does GLOBAL_IN_XXX mean GLOBAL_IN[XXX] etc? And does GLOBAL_IN_XXX always map to A.element(XXX+2)? And its always B.element(N+1) = A.elementN?

I'm also going to assume that you can't change A.element1, A.element2 into A.element[], otherwise the soution would be fairly simple wouldn't it?

The most portable solution is to know the offset of each element in A and B (in case there are data alignment gotchas in the stuctures... could occur if you don't have N consecutive ELEMENT_TYPES etc)

#include <stddef.h>


// NOTE: These arrays are clumbsy but avoid making assumptions about member alignment 
// in strucs. 
static size_t const A_Offsets[] = {
    offsetof(struct A, element1),
    offsetof(struct A, element2),
    offsetof(struct A, element3),
    ...
    ...
    offsetof(struct A, elementN) };


static size_t const B_Offsets[] = {
    offsetof(struct B, element1),
    offsetof(struct B, element2),
    offsetof(struct B, element3),
    ...
    ...
    offsetof(struct B, elementN) };


void myFunctionSingle( structB *B, unsigned int index )
{
    structA  A;
    ELEMENT_TYPE *elAPtr = (ELEMENT_TYPE *)((char *)A + A_Offsets[index + 2]);
    ELEMENT_TYPE *elBPtr = (ELEMENT_TYPE *)((char *)A + B_Offsets[index + 6]);


    if( reqGetFunction( GLOBAL_IN[index], ( void *)&A, SIZE ) != 0 )
    {            
        *elAPtr = -1;
        printf( "element%u failed\n", index);
    }
    *elBPtr = *elAPtr; // A is gotten when regGetFunction() is called      
}

void myFunction( structB *B )
{
    unsigned int i = 1;
    for(; i < MAX_INDEX; ++i)
        myFunctionSingle(B, i);
}

EDIT: I'm not sure if the offsetof() stuff is necessary because if you structure has only ELEMENT_TYPE data in it they are probably packed tight, but I'm not sure... if they are packed tight, then you don't have any data alignment issues so you could use the solution presented in Boston Walker's answer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top