Thread: assigning a structure as a unit

  1. #1
    Registered User
    Join Date
    Jan 2014
    Posts
    62

    assigning a structure as a unit

    I am reading the book C Programming Language. On Structures, it says:

    "The only legal operations on a structure are copying it or assigning to it as a unit, taking its address with &, and accessing its members."

    What does it mean assigning a structure as a unit?

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    It's referring to assigning to a variable of a struct type, from another struct variable (of the same type), so it assigns all of the members at once instead of you assigning them one-by-one. For example:
    Code:
    $ cat foo.c
    #include <stdio.h>
    
    
    struct foo {
        int a;
        int b;
    };
    
    
    int main(void)
    {
        struct foo x = {.a = 1, .b = 2};
        struct foo y = {.a = 3, .b = 4};
    
    
        x = y;
        printf("After assignment: x.a = %d, x.b = %d\n", x.a, x.b);
    
    
        return 0;
    }
    
    
    $ make foo
    gcc -Wall -ggdb3 -pedantic -std=gnu99 -O0 -o foo foo.c -lm -lpthread -lrt
    
    
    $ ./foo
    After assignment: x.a = 3, x.b = 4

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,795
    Quote Originally Posted by anduril462 View Post
    It's referring to assigning to a variable of a struct type, from another struct variable (of the same type), so it assigns all of the members at once instead of you assigning them one-by-one. For example:
    Code:
    #include <stdio.h>
    
    struct foo {
        int a;
        int b;
    };
    
    struct foo2 {
        int a;
        int b;
        int extra;
    };
    
    int main(void)
    {
        struct foo bar = { .a = 42, .b = 43 };
        struct foo2 bar2;
        
        bar2 = *((struct foo2 *)&bar);
    
        printf("a = %d b = %d\n", bar2.a, bar2.b);
    
        return 0;
    }
    
    $ gcc -pedantic -std=c99 s.c 
    
    $ ./a.out
    
    a = 42 b = 43
    Legal, not legal, implementation defined?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,204
    > bar2 = *((struct foo2 *)&bar);
    Not legal.
    1. The cast causes out of bound memory accesses by pretending that the struct is larger than it really is.
    2. Depending on the extra members of foo2, it may have different alignment requirements as well.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    3. Even if the code was well-defined, you aren't making the point you think because specifically you told the compiler the assignment is of the same type.

    That said, I'm pretty sure that would be the same as "out-of-bounds" access which I believe is "undefined-behavior".

    [Edit]
    I posted a second example to elaborate on what Salem posted.
    [/Edit]

    Soma

    Code:
    *(&bar); // this is an instance of `foo'
    *((struct foo2 *)&bar); // you've told the compiler that this is an instance of `foo2'
    Code:
    #include <stdio.h>
    
    struct foo {
        int a;
        int b;
    };
    
    struct foo2 {
        int a;
        int b;
        int extra;
    };
    
    void Dump(struct foo2 * bar2){printf("a = %d b = %d extra = %d\n", bar2->a, bar2->b, bar2->extra);}
    
    int main(void)
    {
        int maybe[1] = {44};
        {
            struct foo bar = { .a = 42, .b = 43 };
            Dump((struct foo2 *)&bar);
            /* bar2->extra is set according to what memory */
            bar.a = 46; /* maybe */
        }
        {
            int bar[2] = {44, 45};
            Dump((struct foo2 *)&bar);
            /* bar2->extra is set according to what memory */
        }
        return 0;
    }
    Last edited by phantomotap; 02-22-2014 at 03:48 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  6. #6
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,795
    Quote Originally Posted by Salem View Post
    > bar2 = *((struct foo2 *)&bar);
    Not legal.
    1. The cast causes out of bound memory accesses by pretending that the struct is larger than it really is.
    2. Depending on the extra members of foo2, it may have different alignment requirements as well.
    Yes, that's true. Another question may be required!

    Edit: Is it really an "out of bound memory access" if that memory is never accessed?

    Quote Originally Posted by phantomotap View Post
    O_o

    3. Even if the code was well-defined, you aren't making the point you think because specifically you told the compiler the assignment is of the same type.

    That said, I'm pretty sure that would be the same as "out-of-bounds" access which I believe is "undefined-behavior".
    I'm asking out of interest.

    A different, and possibly more realistic example. Perhaps this avoids alignment issues

    Code:
    #include <stdio.h>
     
    struct foo {
        int a;
        int b;
    };
     
    struct foo2 {
        struct foo link;
        int extra;
    };
     
    int main(void)
    {
        struct foo2 bar;
        struct foo bar2;
    
        bar.link.a = 42;
        bar.link.b = 43;     
    
        bar2 = *((struct foo *)&bar);
     
        printf("a = %d b = %d\n", bar2.a, bar2.b);
     
        return 0;
    }

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    A different, and possibly more realistic example. Perhaps this avoids alignment issues.
    O_o

    The example may avoid alignment issues, but the example still has "out-of-bounds" access.

    The compiler doesn't "see" a `foo' structure having two integers; the compiler "sees" a `foo2' structure which has three integers; the compiler copies three integers.

    As before, the situation you ask about isn't a "different types" situation as far as the compiler is concerned. Yes. The types are actually different, but you told the compiler that the types are the same, and so the compiler does exactly what it would do if the types actually were the same.

    [Edit]
    I think I possible see the problem.

    Code:
    printf("a = %d b = %d\n", bar2.a, bar2.b);
    The use of `bar2' after being assigned is irrelevant.

    Code:
    bar2 = *((struct foo *)&bar);
    The use of `bar' is relevant. The compiler assigns a value to `bar2.extra' because it is used with the assignment line. The "out-of-bounds" access happens because the compiler assigns `bar2.extra' from `((struct foo *)&bar)->extra' which does not exist.
    [/Edit]

    Soma

    Code:
    #include <stdio.h>
    
    struct foo {
        int a;
        int b;
    };
    
    struct foo2 {
        struct foo link;
        int extra;
    };
    
    void Dump(struct foo2 * bar2){printf("a = %d b = %d extra = %d\n", bar2->link.a, bar2->link.b, bar2->extra);}
    
    int main(void)
    {
        struct foo2 bar2;
        int maybe[1] = {44};
        {
            struct foo bar = { .a = 42, .b = 43 };
            Dump((struct foo2 *)&bar);
            /* bar2->extra is set according to what memory */
            bar.a = 46; /* maybe */
        }
        {
            int bar[2] = {44, 45};
            Dump((struct foo2 *)&bar);
            /* bar2->extra is set according to what memory */
        }
        return 0;
    }
    Last edited by phantomotap; 02-22-2014 at 04:10 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  8. #8
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,795
    Quote Originally Posted by phantomotap View Post
    O_o

    The example may avoid alignment issues, but the example still has "out-of-bounds" access.

    The compiler doesn't "see" a `foo' structure having two integers; the compiler "sees" a `foo2' structure which has three integers; the compiler copies three integers.
    Why would the compiler copy three integers after I've cast it to struct foo which only has two integers? I expect the compiler would only copy two integers and therefore .extra would remain uninitialised... so, Dump() in your example would be accessing uninitialised memory, and that's all, as far as I can see

  9. #9
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Why would the compiler copy three integers after I've cast it to struct foo which only has two integers?
    O_o

    I see that you've changed the types of `bar' and `bar2' on me.

    I expect the compiler would only copy two integers
    In the current code from post #6, the compiler would only copy two integers because both types used in the assignment are `foo' which only has two integers.

    therefore .extra would remain uninitialised... so, Dump() in your example would be accessing uninitialised memory, and that's all, as far as I can see
    You are wrong; You swapped the types of `bar' and `bar2'; I did not.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  10. #10
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,795
    Quote Originally Posted by phantomotap View Post
    O_o

    I see that you've changed the types of `bar' and `bar2' on me.



    In the current code from post #6, the compiler would only copy two integers because both types used in the assignment are `foo' which only has two integers.



    You are wrong; You swapped the types of `bar' and `bar2'; I did not.

    Soma
    I think we were just out of sync. I swapped them in my 2nd example and it seems that you were working on your post before you saw that.

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I think we were just out of sync. I swapped them in my 2nd example and it seems that you were working on your post before you saw that.
    O_o

    Yep.

    *shrug*

    It happens.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  12. #12
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,795
    Quote Originally Posted by phantomotap View Post
    It happens.
    It does. We need some kind of resolve conflict mechanism like git.

  13. #13
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    It does. We need some kind of resolve conflict mechanism like git.
    O_o

    I like the idea; even a simple "some posts were edited since you hit reply" would be handy.

    If you hit "Reply With Quote", I can see an AJAX event triggered for specific posts.

    o_O

    Well, that may--been a long time--not be possible with the "full weight" of "vBulletin"; the tagging over "has been edited" is often loose--up to several minutes if no one has visited the page.

    Still, I like the idea enough to toss the suggestion to a "Drupal" forum developer I know.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Strtok-assigning tokens to structure
    By anya in forum C Programming
    Replies: 9
    Last Post: 12-13-2012, 03:14 AM
  2. assigning value to a char array in a structure
    By Clayg in forum C Programming
    Replies: 11
    Last Post: 11-20-2011, 06:31 PM
  3. Assigning structure elements to an array
    By anndruu12 in forum C Programming
    Replies: 14
    Last Post: 12-08-2010, 05:25 PM
  4. Help assigning memory to structure arrays
    By pk68 in forum C++ Programming
    Replies: 10
    Last Post: 11-29-2010, 07:37 AM
  5. Replies: 2
    Last Post: 05-12-2010, 10:10 AM