Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

struct mystruct a = b; Is this valid? Direct assignment of structure variables, is it valid in C?

Tags:

c

coding-style

I have the following code.

struct rectangle {
int length;
int breadth;
};

int main (void) 
{
    struct rectangle a,b;
    a.length = 10;
    a.breadth = 5;

    b=a;  
    printf("\nValues of b.length = %d, b.breadth=%d\n",b.length,b.breadth);
    return 0;
}

Is the above assignment a valid statement?(b=a) I did it this way inside my project. I got a review comment stating, this type of assignment is wrong and i should have done used memcpy. I printed the values of b and checked. The values are correct. I was wondering why the above assignment is wrong? If it is wrong what happens when you pass a structure variable to a function and catch it in a separate variable? I hope i am clear on my question. Please get back to me if i am unclear on my question.

like image 529
Sandeep Avatar asked Jul 11 '12 11:07

Sandeep


2 Answers

The reviewer is, in my opinion, misguided. It's very correct, struct values are just like any other, it's just fine to assign them. And it's way, way, clearer than invoking memcpy(), and much (much!) less error-prone.

I always have to stop and think about what to pass as the third argument to memcpy() when copying the same type of value, since I find it non-obvious which choice is the clearest. So, that's one less pedagogical problem, and of course it just reads better.

Also, the compiler might be smart enough not to copy any additional padding and/or alignment bytes that might lurk in there, something memcpy() can never do. It's a higher-level construct, and thus "simply better".

like image 158
unwind Avatar answered Sep 29 '22 19:09

unwind


It is, and I think always has been, valid code and your review comment is wrong.

In my view the review comment is bad because the reviewer is misleading you into bad habits - we use memcpy when we want to copy arbitrary bits of memory - and by definition a struct is well defined and it's cleaner, easier to read, and simply your way is right.

If you pass a struct by value to a function, e.g.

struct a some_function(struct a)
{
    a.width = 99;
    return a;
}

The value passed in is a copy, and the return value is also a copy, the only danger here is when the struct is big and results in an overhead for each call.

If this didn't work then most of the C world would fall apart...

To take onboard the reviewers comments, in my opinion they are digging themselves deeper into a whole and should just admit being wrong.

There is no difference between the two statements

memcpy(&b, &a, sizeof(b));
b = a;

If a compiler is optimising then it shouldn't break the original code; otherwise that's a fault in the compiler - it's hokum mentioning the original C standard (i.e. C89) as I doubt very much that the standard permits faulty optimisation.

For interest, rather than proof of anything I just tried this on a pre-ansi compiler (from 1986) in a standard unix environment.

/tmp> gcc a.c
a.c:
C-68000U 1.8.0 Copyright (c)1985,1986 Green Hills Software, Inc.
linking a:
/tmp> ./a
10, 5

For further interest, maybe only mine! I've built with optimisation and looked at the generated code.

The results show that this ancient, pre standard compiler works as expected. The proof in 68k is below - I've added comments with // to explain what's happening.

As you can see, the only result of optimising is that the generated code is more efficient both in terms of space and also execution time - not that that matters much unless you're working in an embedded environment

    ;       line  #13 memcpy(&b, &a, sizeof(b));
     140     PEA    0x8           // size
     144     PEA    (-8,FP)       // &a
     148     PEA    (-16,FP)      // &b
     152     JSR    memcpy        // call memcpy

    ;       line  #14
     170     LEA    (-8,FP),A1   // &a
     174     LEA    (-16,FP),A0  // &b
     178     MOVE.L (A1)+,(A0)+  // copy first element of struct
     180     MOVE.L (A1)+,(A0)+  // copy second element

for a larger struct the code generated for b=a is

     170     LEA    (-112,FP),A1
     174     LEA    (-224,FP),A0
     178     MOVEQ  #27,D0
     180     MOVE.L (A1)+,(A0)+
     182     DBF    D0,main+60

which is exactly the same size as the memcpy version - but will execute faster.

So in summary the original reviewer was wrong and is still wrong and should admit their mistake - unless they are referring to a specific case that they can prove (which I doubt)

like image 25
Richard Harrison Avatar answered Sep 29 '22 19:09

Richard Harrison