4

So, basically, I want to addify every member of first struct, with every member of second struct, and the structs are of same type. Like this:

struct Foo
{
    int bar1;
    int bar2;
    int bar3;
    int bar4;
    int bar5;
}

Foo AddFoos(Foo foo1, Foo foo2)
{
    Foo foo3;
    foo3.bar1 = foo1.bar1 + foo2.bar1;
    foo3.bar2 = foo1.bar2 + foo2.bar2;
    foo3.bar3 = foo1.bar3 + foo2.bar3;
    foo3.bar4 = foo1.bar4 + foo2.bar4;
    foo3.bar5 = foo1.bar5 + foo2.bar5;
    return foo3;
}

However, when structs keep getting bigger, this way is weird. Is there any way to do it with less lines of code? And preferably without advanced pointer magic?

pampeho
  • 704
  • 6
  • 12

4 Answers4

4

Use an array instead and a for loop to add the numbers:

struct Foo
{
    int bars[100];
};

for (i=0;i<100;i++)
{
foo3.bars[i]=foo1.bars[i]+foo2.bars[i];
}

You can malloc if the array size is unknown at compile time and change the struct to this and then malloc for all three Foo variables.

struct Foo
    {
        int *bars;
    };
P.P
  • 117,907
  • 20
  • 175
  • 238
3

Depending on what you call "advanced pointer magic", you can use the following moderately magical code:

Foo AddFoos(Foo foo1, Foo foo2)
{
    Foo foo3;
    int *pointer1 = &foo1.bar1; // first field here
    int *pointer2 = &foo2.bar1; // first field here
    int *pointer3 = &foo3.bar1; // first field here
    while (pointer3 <= &foo3.bar5) // last field here
    {
        *pointer3++ = *pointer1++ + *pointer2++;
    }
    return foo3;
}

When you change the definition of Foo, just update the names of the first and last field. This will only work when all fields are of the same type.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
3

You want the comfort of named fields (bar1 .. barN) and something like an array you can loop over to automate the operations. First we define the struct (a dense representation of the fields in memory):

struct VectorFields {
    int a;
    int b;
    int c;
};

Then we need to get to know the number of the fields used in that struct:

#define VECTOR_FIELDS_LEN (sizeof(struct VectorFields) / sizeof(int))

(In C++ you could use some template magic foo, here we just use the preprocessor as a simpler variant). Next, we combine the struct VectorFields with an array of int so both match in size, also known as union:

union Vector {
    struct VectorFields fields;
    int raw[VECTOR_FIELD_LEN];
};

(Note: VECTOR_FIELD_LEN must be a known constant value to the compiler, hence the preprocessor thingy before.) You are now able to access the data either by it's name (.fields.a) or by an index (.raw[0]). So, let's write the function which adds the Vector together:

void vector_add(union Vector* result, union Vector* a, union Vector* b) {
    int i;
    for (i = 0; i < TUPLE_LEN; i++) {
        result->raw[i] = a->raw[i] + b->raw[i];
    }
}

You might use it like this then:

#include <stdio.h>
int main() {
    union Vector a = { .fields = { 1, 2, 3 } };
    union Vector b = { .fields = { 4, 5, 6 } };
    union Vector sum;

    vector_add(&sum, &a, &b);

    printf("%d %d %d\n", sum.fields.a, sum.fields.b, sum.fields.c);
    return 0;
}
akira
  • 6,050
  • 29
  • 37
  • Explanation? This is not a trivial one-liner. –  Nov 22 '12 at 19:11
  • It's a union between a structure and an array. Wow. Does it work only on a structure with only one member type? – pampeho Nov 22 '12 at 19:20
  • @Zupoman: yes, the whole 'lets loop over the fields' works only with the same type for everything you loop over. welcome in c-land (and c++). you can make it work for any type by adding meta-information next to the type and come up with something that gets closer and closer to an interpreted language (think void* magic + type related info) but as soon as you take this path you will _really_ decrease any readibility of your code. – akira Nov 22 '12 at 19:25
  • Beware: I remember having read some C++ standards mentioning that this C-union-write-here-read-there-trick is not guaranteed to work in C++ and even possbibly not for C99. – alk Nov 22 '12 at 19:27
  • @alk: the union itself will work, regardless of the type of the fields. the adding will work as well. the problem starts when your fields are doubles and you add them together inside a int-array: strange results. for something like `struct { char a; char b; char c; };` might even work, you would 'parallize' the addition, very special case, unwise to do it. – akira Nov 22 '12 at 19:29
  • related: http://stackoverflow.com/questions/1972003/how-to-use-anonymous-structs-unions-in-c – akira Nov 22 '12 at 19:43
  • Thanks for the link, as I was referring to the standard cited in the comments to this answer: http://stackoverflow.com/a/1972098/694576 @akira – alk Nov 22 '12 at 19:57
1

If you have only ints you can use an array

struct Foo {
    int bar[5];
};

Foo AddFoos(Foo f1, Foo f2)
{
    Foo f3;
    int i;
    for (i = 0; i < 5; ++i)
        f3.bar[i] = f1.bar[i] + f2.bar[i];

    return f3;
}
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198