Re: Copying Aggregate Data Types in C

Discussion in 'C Programming' started by CBFalconer, Dec 17, 2008.

  1. CBFalconer

    CBFalconer Guest

    Jujitsu Lizard wrote:
    >
    > In the general case, if s1 and s2 are structures, am I allowed to
    > just use:
    > s1 = s2;


    Yes, provided s1 and s2 are the same struct type. What you cannot
    do (because of padding, etc) is compare them for equality. i.e.:

    if (s1 == s2) ...

    is not legal.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
     
    CBFalconer, Dec 17, 2008
    #1
    1. Advertising

  2. On Dec 18, 6:43 am, CBFalconer <> wrote:

    > Yes, provided s1 and s2 are the same struct type.  What you cannot
    > do (because of padding, etc) is compare them for equality.  i.e.:
    >
    >     if (s1 == s2) ...
    >
    > is not legal.




    I'm very surprised at this. I tried it just there with a C compiler
    and also with a C++ compiler, and both gave a compiler error. I don't
    see why they couldn't have made the comparison result in a comparison
    of all members, something like:

    #define (a == b) (a.i == b.i && a.j == b.j && a.k == b.k)

    So if you want to compare two structs for equality (I'm talking value
    equality as opposed to binary equality), then you actually have to
    verbosely compare member by member? That's a pain.
     
    Tomás Ó hÉilidhe, Dec 18, 2008
    #2
    1. Advertising

  3. CBFalconer

    Sjouke Burry Guest

    Tomás Ó hÉilidhe wrote:
    > On Dec 18, 6:43 am, CBFalconer <> wrote:
    >
    >> Yes, provided s1 and s2 are the same struct type. What you cannot
    >> do (because of padding, etc) is compare them for equality. i.e.:
    >>
    >> if (s1 == s2) ...
    >>
    >> is not legal.

    >
    >
    >
    > I'm very surprised at this. I tried it just there with a C compiler
    > and also with a C++ compiler, and both gave a compiler error. I don't
    > see why they couldn't have made the comparison result in a comparison
    > of all members, something like:
    >
    > #define (a == b) (a.i == b.i && a.j == b.j && a.k == b.k)
    >
    > So if you want to compare two structs for equality (I'm talking value
    > equality as opposed to binary equality), then you actually have to
    > verbosely compare member by member? That's a pain.

    So write a function:
    int ismystructequal(mystruct a,mystruct b){
    return(a.i == b.i && a.j == b.j && a.k == b.k)
    }
    Or something like that.
    But you might have problems if the struct contains arrays and/or
    pointers.
    Should the pointers be equal, or should the data pointed to, be equal?
    And a host of other problems when the struct becomes more obscure.
    You quickly reach a point where the compiler knows less than you do,
    and therefore the compiler rightly leaves that job to the programmer.
     
    Sjouke Burry, Dec 18, 2008
    #3
  4. On 18 Dec 2008 at 5:27, Tomás Ó hÉilidhe wrote:
    > So if you want to compare two structs for equality (I'm talking value
    > equality as opposed to binary equality), then you actually have to
    > verbosely compare member by member? That's a pain.


    In C++ of course, you can overload the == operator.

    If you're doing object-oriented programming in C, yes, you need to be
    more verbose, e.g. having mytype_isequal() functions/macros. But then
    you also need to have a mytype_init() function rather than having a
    constructor.

    While OO programming can be done perfectly well in C, C wasn't designed
    with OO in mind, so an OO approach does lead to quite verbose code. Look
    at glib as the ultimate example of this!
     
    Antoninus Twink, Dec 18, 2008
    #4
  5. CBFalconer

    Chris Dollin Guest

    Tomás Ó hÉilidhe wrote:

    > On Dec 18, 6:43 am, CBFalconer <> wrote:
    >
    >> Yes, provided s1 and s2 are the same struct type.  What you cannot
    >> do (because of padding, etc) is compare them for equality.  i.e.:
    >>
    >> if (s1 == s2) ...
    >>
    >> is not legal.

    >
    > I'm very surprised at this. I tried it just there with a C compiler
    > and also with a C++ compiler, and both gave a compiler error. I don't
    > see why they couldn't have made the comparison result in a comparison
    > of all members, something like:
    >
    > #define (a == b) (a.i == b.i && a.j == b.j && a.k == b.k)


    Because that's often the wrong answer. Consider (a) structs with
    `char*` members: what's the (one, single, only) right way to compare them?
    Consider (b) this (illustrative) example:

    struct SmallStringBuffer { char[17] content; int size; }

    I have in my left hand a StringBuffer with content [`A`, 0 (16)]
    (the parenthesised number is a repeat count), and size 1, and in my
    right hand one with size 1 and content [`A`, `B` (16)]. Are they
    equal?

    If the compiler/language can't guess the right answer often enough,
    perhaps it doesn't need to guess at all.

    > So if you want to compare two structs for equality (I'm talking value
    > equality as opposed to binary equality), then you actually have to
    > verbosely compare member by member? That's a pain.


    Slightly. But only slightly: that's why the gods gave us functions.

    Of course, it would be nice if it was easy to use the functions without
    lots of syntactic clutter. But lets not overload this response with that
    discussion.

    --
    "We dance, and the worlds melt away." - Curved Air, /Metamorphosis/

    Hewlett-Packard Limited registered no:
    registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
     
    Chris Dollin, Dec 18, 2008
    #5
  6. On Dec 18, 4:32 pm, Antoninus Twink <> wrote:

    > While OO programming can be done perfectly well in C,
    > C wasn't designed
    > with OO in mind, so an OO approach does lead to quite verbose code. Look
    > at glib as the ultimate example of this!




    I think it's a great exercise to take some complicated C++ code
    (containing stuff like virtual functions), and rewrite it in C. I
    first did this myself a few years ago and learned loads from it. C++
    is taught in a "black box" way by most books and by most institutions;
    they portray such things as virtual functions as "magic". They'll show
    you how to use virtual functions, but never actually show how they
    work in terms of machine code (or even in terms of C). I first learned
    about virtual functions from reading "C++ for Dummies", and my first
    reaction was "Holy shit that's amazing, how does the called function
    know the type of the object being passed?!". That bugged me for a
    while until I found out about VTable's... and of course then I had to
    write my own VTable code in C to see if I could get it working. When I
    got it working I was like "so it's not magic after all", and then I
    was comfortable with my understanding of how it worked.

    Yeah a lot of the OO things in C++ can be achieved in C just by using
    pointers and helper functions such as "void MyClass_Construct(void)",
    but if you bring templates into the picture then the C code becomes an
    absolute dog's dinner. And there's definitely loads of stuff you can
    do with templates in C++ which can't do /at all/ in C.

    The only reason I write C code, as opposed to C++ code, is that it's
    more portable. I mean if a particular platform has /any/ kind of
    compiler, there's a strong likelihood of it being a C compiler. Plus
    it's rare that I feel the need for OO programming (but there
    definitely are cases where I opt for C++ because it has some really
    elegant ways of solving particular problems).
     
    Tomás Ó hÉilidhe, Dec 18, 2008
    #6
  7. In article <gid8v1$5u1$>,
    Chris Dollin <> wrote:

    >Because that's often the wrong answer. Consider (a) structs with
    >`char*` members: what's the (one, single, only) right way to compare them?


    Consider two char * variables: what's the one right way to compare
    them?

    It's hardly in the spirit of C to reject something because it's not
    always what you need.

    (I use that phrase because the Rationale rejects structure comparisons
    on the grounds that it might involve an arbitrarily long sequence of
    instructions, which is "not in the spirit of C".)

    -- Richard
    --
    Please remember to mention me / in tapes you leave behind.
     
    Richard Tobin, Dec 18, 2008
    #7
  8. In article <>,
    Anthony Fremont <> wrote:

    >> (I use that phrase because the Rationale rejects structure comparisons
    >> on the grounds that it might involve an arbitrarily long sequence of
    >> instructions, which is "not in the spirit of C".)


    >LOL Where does that leave printf?


    That's not fair: printf() is a function, not a language feature.

    You could make a better case with switch, I think.

    -- Richard
    --
    Please remember to mention me / in tapes you leave behind.
     
    Richard Tobin, Dec 18, 2008
    #8
  9. In article <>,
    Anthony Fremont <> wrote:

    >Ok, that's true. I still think a simple == or != comparison would be no
    >more instruction intensive than the assignment operation is.


    The comparison operations have to ignore padding, so can't generally
    be compiled into something as simple as memmove().

    >IMO, switch should be efficient on most hardware since the case labels
    >require a constant expression. Or am I missing something?


    Switch is typically compiled into a jump table when the cases have
    contiguous (or nearly so) values, and a sequence of tests and
    conditional jumps if they are "random", but I have seen cases where a
    single switch produces a long sequence of tests, jumps, and tables.
    Of course, such cases arise from switches occupying long stretches of
    source code, unlike a comparison.

    -- Richard
    --
    Please remember to mention me / in tapes you leave behind.
     
    Richard Tobin, Dec 18, 2008
    #9
  10. CBFalconer

    Chris Dollin Guest

    Richard Tobin wrote:

    > In article <gid8v1$5u1$>,
    > Chris Dollin <> wrote:
    >
    >>Because that's often the wrong answer. Consider (a) structs with
    >>`char*` members: what's the (one, single, only) right way to compare them?

    >
    > Consider two char * variables: what's the one right way to compare
    > them?


    The compiler doesn't /implicitly/ generate code for comparing
    two char* values: unlike the proposed case of struct members,
    where the decision has to be made automagically, you write
    what you want.

    > It's hardly in the spirit of C to reject something because it's not
    > always what you need.


    It's in the spirit of C not to pre-empt decisions that the programmer
    might want to make differently.

    > (I use that phrase because the Rationale rejects structure comparisons
    > on the grounds that it might involve an arbitrarily long sequence of
    > instructions, which is "not in the spirit of C".)


    And yet it doesn't reject function calls on the grounds that they
    might involve arbitrarily long sequence of instructions, nor function
    bodies on the same basis. It's not, I belive, that the sequences are
    /long/; it's that they're /hidden/ and long, so that `a == b` might
    "unexpectedly" generate wads of code or "unexpectedly" be "inefficient".

    I find the long-sequence objection far less compelling than the what-meaning
    objection, but in any case am not advocating a change to the C `==`
    definition, that fight having been lost or rendered irrelevant a long
    time ago.

    --
    "It's just the beginning we've seen." - Colosseum, /Tomorrow's Blues/

    Hewlett-Packard Limited registered no:
    registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
     
    Chris Dollin, Dec 18, 2008
    #10
  11. "Anthony Fremont" <> writes:

    > Richard Tobin wrote:
    >> In article <>,
    >> Anthony Fremont <> wrote:
    >>
    >>>> (I use that phrase because the Rationale rejects structure
    >>>> comparisons on the grounds that it might involve an arbitrarily
    >>>> long sequence of instructions, which is "not in the spirit of C".)

    >>
    >>> LOL Where does that leave printf?

    >>
    >> That's not fair: printf() is a function, not a language feature.
    >>
    >> You could make a better case with switch, I think.

    >
    > Ok, that's true. I still think a simple == or != comparison would be no
    > more instruction intensive than the assignment operation is.


    Because some types can be multi-valued (pointer are the obvious
    example) a simple bit-wise compare is not always possible. In general
    == would have to turn into a recursively generated set of ==
    operations. Structure padding is, effectively, the same issue. Two
    structure may compare equal wthout being bit-wise equal because of the
    padding.

    --
    Ben.
     
    Ben Bacarisse, Dec 18, 2008
    #11
  12. On Dec 18, 10:17 pm, Chris Dollin <> wrote:

    > I find the long-sequence objection far less compelling than the what-meaning
    > objection, but in any case am not advocating a change to the C `==`
    > definition, that fight having been lost or rendered irrelevant a long
    > time ago.




    There's no point in advocating /any/ changes to C if you ask me...
    better to spend your time focusing on bandaids and workarounds.

    The situation's a little better with C++ as regards being able to
    change and develop the language, but even if you were to come up with
    a brilliant idea today it'd probably be 20 years before it actually
    makes it into the language. I contacted Bjarne Stroustrup recently to
    ask if he was planning a new book to reflect the coming standard of C+
    +, and his response was as follows:

    "I plan to write a 4th edition, but it'll take me a year or two.
    Similarly, it'll take the implementers a year or two to get it all
    ready for use."
     
    Tomás Ó hÉilidhe, Dec 18, 2008
    #12
  13. CBFalconer

    Phil Carmody Guest

    (Richard Tobin) writes:
    > In article <>,
    > Anthony Fremont <> wrote:
    >
    >>> (I use that phrase because the Rationale rejects structure comparisons
    >>> on the grounds that it might involve an arbitrarily long sequence of
    >>> instructions, which is "not in the spirit of C".)

    >
    >>LOL Where does that leave printf?

    >
    > That's not fair: printf() is a function, not a language feature.
    >
    > You could make a better case with switch, I think.


    Or the comma operator...

    Phil
    (Of course, expressions can grow horrifically large without ',',
    I was just just arbitrarily picking one that's practically designed
    for making arbitrarily long sequences of instructions.)
    --
    I tried the Vista speech recognition by running the tutorial. I was
    amazed, it was awesome, recognised every word I said. Then I said the
    wrong word ... and it typed the right one. It was actually just
    detecting a sound and printing the expected word! -- pbhj on /.
     
    Phil Carmody, Dec 18, 2008
    #13
  14. "Anthony Fremont" <> writes:

    > I just see these as simple problems to fix. One way is to force assignment
    > _and_ structure compare to work the same way. It seems that the standard
    > could either:
    > 1) Force all padding to a known value such as everybodys favorite \0. This
    > seems the common sense way to do it, then assignment and compare would
    > include the padding for a net effect of nothing.
    > OR
    > 2) Forcibly exclude padding from assignments and comparisons.
    >
    > The first way would obviously be the most efficient and I can think of no
    > reason to not do it other than some petty whining about initializing
    > "unused" memory. But nobody gripes that crt0.S does it to all of RAM just
    > to satisfy the standard's idea of what the environment .


    I suppose you're referring to the requirement that static objects are
    initialized to zero. But that only happens once. Consider the effect
    of your proposal (1) on

    void foo(void) {
    struct big array[1000];
    fill_in_array(array, 1000);
    /* ... */
    }

    The compiler is going to have to generate code to initialize all 1000 of
    the elements of `array' (or at least the padding, but it would probably
    be faster to zero out the whole thing if possible), since as far as it
    knows, `fill_in_array' might do some comparisons. In this case, it
    doesn't, and all that effort is wasted, *every time foo() is called*.
    This has a much greater impact on the program's efficiency.

    > As long as you just want == or != comparison, I don't see why it can't be
    > implemented with very little pain. Granted I haven't worked on all
    > platforms, but I've written assembly on more than a couple. I guess I need
    > to read the Rationale. All in all, it looks to me like allowing structure
    > assignment was just an ugly hack to allow functions to return auto-defined
    > versions of them.


    I can't parse that last sentence.

    > I always thought this whole structure assignment thing was inconsitent with
    > the way that other "similar" data types like arrays and strings are handled.


    It is inconsistent with the handling of arrays, yes. I would argue that
    "strings" are not a data type in C, but instead an agreed-upon way to
    use the data types "array of char" and "pointer to char".

    > Please try to forgive me if I misuse terminology sometimes, especially with
    > the baffling way that K&R uses definition and declaration.


    As a digression, I find a good way to remember the difference is that a
    definition causes some code to be generated, while a declaration
    doesn't.

    Given the definition

    int foo(int x, int y) { return x + y; }

    the compiler will generate some assembly code for the function `foo'.
    Given the declaration

    int bar(int x, int y);

    it won't generate any assembly, it will just remember for itself that
    "Hmm, there's a function called bar. Now I will know what to do if
    someone ever decides to call it."

    The rule for data objects is similar, with a slight exception for
    "tentative definitions".

    > I'm not a C expert.


    Spending much time on this newsgroup is a good way to learn a lot more
    about it, if you want to, in spite of the noise and trolling.
     
    Nate Eldredge, Dec 18, 2008
    #14
  15. CBFalconer

    CBFalconer Guest

    Anthony Fremont wrote:
    > Richard Tobin wrote:
    >
    >> (I use that phrase because the Rationale rejects structure
    >> comparisons on the grounds that it might involve an arbitrarily
    >> long sequence of instructions, which is "not in the spirit of
    >> C".)

    >
    > LOL Where does that leave printf?


    For one thing, printf is an interpreter. It interprets the format
    string.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
     
    CBFalconer, Dec 18, 2008
    #15
  16. Phil Carmody <> writes:

    > (Richard Tobin) writes:
    >> In article <>,
    >> Anthony Fremont <> wrote:
    >>
    >>>> (I use that phrase because the Rationale rejects structure comparisons
    >>>> on the grounds that it might involve an arbitrarily long sequence of
    >>>> instructions, which is "not in the spirit of C".)

    >>
    >>>LOL Where does that leave printf?

    >>
    >> That's not fair: printf() is a function, not a language feature.
    >>
    >> You could make a better case with switch, I think.

    >
    > Or the comma operator...
    >
    > Phil
    > (Of course, expressions can grow horrifically large without ',',
    > I was just just arbitrarily picking one that's practically designed
    > for making arbitrarily long sequences of instructions.)


    But that is missing the point. Every instance of every operator
    (currently) adds just a little compiled code to the program. The
    argument is that == would add a potentially unlimited amount from
    one instance of the operator.

    --
    Ben.
     
    Ben Bacarisse, Dec 19, 2008
    #16
  17. "Anthony Fremont" <> writes:

    > Ben Bacarisse wrote:
    >> "Anthony Fremont" <> writes:
    >>
    >>> Richard Tobin wrote:
    >>>> In article <>,
    >>>> Anthony Fremont <> wrote:
    >>>>
    >>>>>> (I use that phrase because the Rationale rejects structure
    >>>>>> comparisons on the grounds that it might involve an arbitrarily
    >>>>>> long sequence of instructions, which is "not in the spirit of C".)
    >>>>
    >>>>> LOL Where does that leave printf?
    >>>>
    >>>> That's not fair: printf() is a function, not a language feature.
    >>>>
    >>>> You could make a better case with switch, I think.
    >>>
    >>> Ok, that's true. I still think a simple == or != comparison would
    >>> be no more instruction intensive than the assignment operation is.

    >>
    >> Because some types can be multi-valued (pointer are the obvious
    >> example) a simple bit-wise compare is not always possible. In general

    >
    > I understand that.


    OK, but I don't think your proposed solutions address this part of the
    problem.

    >> == would have to turn into a recursively generated set of ==
    >> operations. Structure padding is, effectively, the same issue. Two
    >> structure may compare equal wthout being bit-wise equal because of the
    >> padding.

    >
    > I just see these as simple problems to fix. One way is to force assignment
    > _and_ structure compare to work the same way. It seems that the standard
    > could either:
    > 1) Force all padding to a known value such as everybodys favorite \0. This
    > seems the common sense way to do it, then assignment and compare would
    > include the padding for a net effect of nothing.


    That would force malloc to zero all data as well. Also, given:

    struct s1 { int i1; char c; int i2; }; /* assume iiiicXXXiiii */
    struct s2 { char c1; int i; char c2; }; /* cXXXiiiicXXX */
    union u { struct s1 s1; struct s2 s2; } u;

    what padding gets set in u and when?

    > OR
    > 2) Forcibly exclude padding from assignments and comparisons.


    This may work but it is not very clear what you mean by it. I think
    most people would end up thinking that to solve the problem of
    comparing values and ignoring padding you have to simply translate the
    operator into a series of == or != operations on the members. Unions
    would probably have to be excluded.

    > The first way would obviously be the most efficient and I can think of no
    > reason to not do it other than some petty whining about initializing
    > "unused" memory. But nobody gripes that crt0.S does it to all of RAM just
    > to satisfy the standard's idea of what the environment .
    >
    > As long as you just want == or != comparison, I don't see why it can't be
    > implemented with very little pain. Granted I haven't worked on all
    > platforms, but I've written assembly on more than a couple. I guess I need
    > to read the Rationale.


    In no way is it hard to define and implement but it does seem
    un-C-like and certainly not very useful.

    > All in all, it looks to me like allowing structure
    > assignment was just an ugly hack to allow functions to return auto-defined
    > versions of them.


    Ah, but seems so wonderful when the v7 compiler arrived in 197(mumble)
    making long int and structure return and assignment possible. (Ever
    wondered why time() takes pointer *and* returns a result?)

    I am not being nostalgic. What may look like a hack now may once have
    been simply a reasonable compromise between competing design objectives.

    --
    Ben.
     
    Ben Bacarisse, Dec 19, 2008
    #17
  18. CBFalconer

    Richard Bos Guest

    (Richard Tobin) wrote:

    > In article <gid8v1$5u1$>,
    > Chris Dollin <> wrote:
    >
    > >Because that's often the wrong answer. Consider (a) structs with
    > >`char*` members: what's the (one, single, only) right way to compare them?

    >
    > Consider two char * variables: what's the one right way to compare
    > them?


    That depends on the context. Sometimes you want ==, sometimes you want
    strcmp(), and sometimes you want memcmp().

    > It's hardly in the spirit of C to reject something because it's not
    > always what you need.


    Contrariwise, it is precisely in the spirit of C to trust the
    programmer, and not to presume to do the thinking for him.

    Richard
     
    Richard Bos, Dec 19, 2008
    #18
  19. In article <4all.nl>,
    Richard Bos <> wrote:

    >> >Because that's often the wrong answer. Consider (a) structs with
    >> >`char*` members: what's the (one, single, only) right way to compare them?


    >> Consider two char * variables: what's the one right way to compare
    >> them?


    >That depends on the context. Sometimes you want ==, sometimes you want
    >strcmp(), and sometimes you want memcmp().


    Right, but that doesn't mean that == shouldn't exist for char *.
    If == existed for structs, sometimes it would be what you want, and
    sometimes it wouldn't.

    >> It's hardly in the spirit of C to reject something because it's not
    >> always what you need.


    >Contrariwise, it is precisely in the spirit of C to trust the
    >programmer, and not to presume to do the thinking for him.


    Providing an operator isn't "doing the thinking for him".

    -- Richard
    --
    Please remember to mention me / in tapes you leave behind.
     
    Richard Tobin, Dec 19, 2008
    #19
  20. CBFalconer

    CBFalconer Guest

    Richard Tobin wrote:
    > Richard Bos <> wrote:
    >

    .... snip ...
    >
    >> That depends on the context. Sometimes you want ==, sometimes
    >> you want strcmp(), and sometimes you want memcmp().

    >
    > Right, but that doesn't mean that == shouldn't exist for char *.
    > If == existed for structs, sometimes it would be what you want,
    > and sometimes it wouldn't.


    Actually, under restricted conditions, it is quite possible that ==
    for structures will work correctly. Consider a system where:

    1. The size is discovered via sizeof
    2. The struct has NO padding bytes.
    3. The work is done by memcmp.

    However, such restricted conditions (and possibly more) do not
    generally exist.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
     
    CBFalconer, Dec 20, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guiding5
    Replies:
    1
    Views:
    1,714
    Dimitre Novatchev
    Feb 28, 2006
  2. ramu
    Replies:
    2
    Views:
    328
    rlblaster
    Feb 20, 2006
  3. Nate Eldredge

    Re: Copying Aggregate Data Types in C

    Nate Eldredge, Dec 17, 2008, in forum: C Programming
    Replies:
    12
    Views:
    668
    Barry Schwarz
    Dec 19, 2008
  4. Gary Roach
    Replies:
    0
    Views:
    114
    Gary Roach
    Sep 1, 2013
  5. Fábio Santos
    Replies:
    0
    Views:
    122
    Fábio Santos
    Sep 4, 2013
Loading...

Share This Page