Array assignment via struct

Discussion in 'C Programming' started by Eric Laberge, Aug 4, 2005.

  1. Eric Laberge

    Eric Laberge Guest

    Hi!

    I'm working on automatically generated code, and need to assign arrays.
    memcpy is an obvious solution, but it becomes complicated to use in the
    context I'm working on, ie.: I could use it but I don't want to.
    Arrays cannot be assigned in C, but structs can, so I coded the
    following:

    #include <stdlib.h>

    int main(void)
    {
    void* a = malloc(10); /* This obviously should be checked for malloc
    failure */
    void* b = malloc(10); /* This too... */

    *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

    free(a);
    free(b);
    return 0;
    }

    I wouldn't have tought that this would compile, let alone not give a
    single warning (gcc -W -Wall -pedantic). It even works :), as I tried
    copying and displaying a string. I can easily code that in my code
    generator (a translator, actually) and I suppose it would even let me
    cast expressions to an array!

    What I'm wondering, since this is not too bad looking as a solution,
    is:
    1) Is this solution common?
    2) Is this portable?
    3) Does this actually respects the C standard? (if not, why?)
    4) Any way to improve this assign without using a function?

    FYI, I tried using anonymous structures:
    *((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
    t[10];}*) b);
    but the compiler complained about incompatible types, which I
    understand the cause. I had to try it, though.

    Thanks
    --
    Eric Laberge
    Eric Laberge, Aug 4, 2005
    #1
    1. Advertising

  2. In article <>,
    Eric Laberge <> wrote:
    >
    > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    >
    > What I'm wondering, since this is not too bad looking as a solution,
    > is:
    > 1) Is this solution common?


    Casting void pointers to struct pointers is *very* common indeed; however,
    declaring a new struct in the middle of a statement...that part is unusual.

    > 2) Is this portable?


    I think so. I tried it on three completely independent
    compilers and they all accepted it in c89 and c99 modes.

    > 3) Does this actually respects the C standard? (if not, why?)


    Dunno. Hopefully someone more fluent with the standard(s) can
    indicate whether it is conforming and to what level (and
    restore my confidence in my three favorite compilers!).

    > 4) Any way to improve this assign without using a function?


    The last time I had to move small chunks of data of size unknown-by-me
    but knowable-by-the-program, I had a menu of different ways to handle it:

    * Small items of 1, 2, 4, or 8 bytes were cast to built-in types of
    the appropriate size (e.g. char thru double).
    * Odd sized things, misaligned data, and larger objects were just passed
    to memcpy().
    * Overlapping data of course gets memmove().

    Doing a struct copy in the source code might map to a memcpy (or worse,
    memmove) in the binary anyway. You'll have to examine the assembly
    output and maybe even profile the code to get a handle on what's
    optimal (which seems to be the subtext of your wanting to avoid
    memcpy).

    Declaring a struct in the middle of doing something else is
    at least visually jarring. I'd probably move the struct
    declaration up and out, or at least replace the statement
    in place with

    do {
    struct copy {unsigned char t[10];};
    *((struct copy *) a) = *((struct copy*) b);
    } while (0)

    and maybe skip the do while(0) stuff it's straight-line generated
    code, but assign unique names to the structs.
    --
    7842++
    Anonymous 7843, Aug 5, 2005
    #2
    1. Advertising

  3. Eric Laberge

    pete Guest

    Netocrat wrote:
    >
    > On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    >
    > > I'm working on automatically generated code,
    > > and need to assign arrays.
    > > memcpy is an obvious solution,
    > > but it becomes complicated to use in the
    > > context I'm working on, ie.: I could use it but I don't want to.
    > > Arrays cannot be assigned in C, but structs can, so I coded the
    > > following:
    > >
    > > #include <stdlib.h>
    > >
    > > int main(void)
    > > {
    > > void* a = malloc(10);
    > > /* This obviously should be checked for malloc
    > > failure */
    > > void* b = malloc(10); /* This too... */
    > >
    > > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    > >
    > > free(a);
    > > free(b);
    > > return 0;
    > > }

    >
    > <snip>
    >
    > The only problem I can see is that the structure is not necessarily
    > the same size as the array
    > - the compiler is free to add padding to the structure.
    >
    > Better to declare the structure first and do sizeof on it to check.


    Use sizeof structure for the argument in the call to malloc.

    /* BEGIN new.c */

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>

    struct copy {
    unsigned char t[10];
    };

    int main(void)
    {
    void *a = malloc(sizeof(struct copy));
    void *b = malloc(sizeof(struct copy));

    if (a == NULL || b == NULL) {
    puts("malloc problem");
    exit(EXIT_FAILURE);
    }
    strcpy(b, "123456789");
    *(struct copy *)a = *(struct copy *)b;
    free(b);
    puts(a);
    free(a);
    return 0;
    }

    /* END new.c */


    --
    pete
    pete, Aug 5, 2005
    #3
  4. Eric Laberge

    Netocrat Guest

    On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

    > I'm working on automatically generated code, and need to assign arrays.
    > memcpy is an obvious solution, but it becomes complicated to use in the
    > context I'm working on, ie.: I could use it but I don't want to.
    > Arrays cannot be assigned in C, but structs can, so I coded the
    > following:
    >
    > #include <stdlib.h>
    >
    > int main(void)
    > {
    > void* a = malloc(10); /* This obviously should be checked for malloc
    > failure */
    > void* b = malloc(10); /* This too... */
    >
    > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    >
    > free(a);
    > free(b);
    > return 0;
    > }


    <snip>

    The only problem I can see is that the structure is not necessarily
    the same size as the array - the compiler is free to add padding to the
    structure.

    Better to declare the structure first and do sizeof on it to check.

    Not really portable because on different platforms different amounts of
    padding may be added. Memcpy is probably simpler.
    Netocrat, Aug 5, 2005
    #4
  5. Eric Laberge

    Netocrat Guest

    On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote:

    > Netocrat wrote:
    >>
    >> On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    >>
    >> > I'm working on automatically generated code,
    >> > and need to assign arrays.
    >> > memcpy is an obvious solution,
    >> > but it becomes complicated to use in the
    >> > context I'm working on, ie.: I could use it but I don't want to.
    >> > Arrays cannot be assigned in C, but structs can, so I coded the
    >> > following:
    >> >
    >> > #include <stdlib.h>
    >> >
    >> > int main(void)
    >> > {
    >> > void* a = malloc(10);
    >> > /* This obviously should be checked for malloc
    >> > failure */
    >> > void* b = malloc(10); /* This too... */
    >> >
    >> > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    >> >
    >> > free(a);
    >> > free(b);
    >> > return 0;
    >> > }

    >>
    >> <snip>
    >>
    >> The only problem I can see is that the structure is not necessarily
    >> the same size as the array
    >> - the compiler is free to add padding to the structure.
    >>
    >> Better to declare the structure first and do sizeof on it to check.

    >
    > Use sizeof structure for the argument in the call to malloc.



    Additions untested; for comment value only...

    > /* BEGIN new.c */
    >
    > #include <stdlib.h>
    > #include <string.h>
    > #include <stdio.h>


    #define ARRSIZE 10

    > struct copy {
    > unsigned char t[ARRSIZE];
    > };
    >
    > int main(void)
    > {

    void *a, b;

    if (sizeof(struct copy) > ARRSIZE) {
    /* do you want to have to potentially deal with this
    * complication? Is it even an issue? */
    }
    a = malloc(sizeof(struct copy));
    b = malloc(sizeof(struct copy));

    >
    > if (a == NULL || b == NULL) {
    > puts("malloc problem");
    > exit(EXIT_FAILURE);
    > }
    > strcpy(b, "123456789");
    > *(struct copy *)a = *(struct copy *)b; free(b); puts(a); free(a);
    > return 0;
    > }
    > }
    > /* END new.c */
    Netocrat, Aug 5, 2005
    #5
  6. Eric Laberge

    Suman Guest

    Netocrat wrote:
    > On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote:
    >
    > > Netocrat wrote:
    > >>
    > >> On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    > >>
    > >> > I'm working on automatically generated code,
    > >> > and need to assign arrays.
    > >> > memcpy is an obvious solution,
    > >> > but it becomes complicated to use in the
    > >> > context I'm working on, ie.: I could use it but I don't want to.
    > >> > Arrays cannot be assigned in C, but structs can, so I coded the
    > >> > following:
    > >> >
    > >> > #include <stdlib.h>
    > >> >
    > >> > int main(void)
    > >> > {
    > >> > void* a = malloc(10);
    > >> > /* This obviously should be checked for malloc
    > >> > failure */
    > >> > void* b = malloc(10); /* This too... */
    > >> >
    > >> > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    > >> >
    > >> > free(a);
    > >> > free(b);
    > >> > return 0;
    > >> > }
    > >>
    > >> <snip>
    > >>
    > >> The only problem I can see is that the structure is not necessarily
    > >> the same size as the array
    > >> - the compiler is free to add padding to the structure.
    > >>
    > >> Better to declare the structure first and do sizeof on it to check.

    > >
    > > Use sizeof structure for the argument in the call to malloc.

    >
    >
    > Additions untested; for comment value only...
    >
    > > /* BEGIN new.c */
    > >
    > > #include <stdlib.h>
    > > #include <string.h>
    > > #include <stdio.h>

    >
    > #define ARRSIZE 10
    >
    > > struct copy {
    > > unsigned char t[ARRSIZE];
    > > };
    > >
    > > int main(void)
    > > {

    > void *a, b;


    Is this really what you want? Typo, I presume. So, we'll change it
    to...
    void *a, *b;
    and the rest follows.

    > if (sizeof(struct copy) > ARRSIZE) {
    > /* do you want to have to potentially deal with this
    > * complication? Is it even an issue? */
    > }
    > a = malloc(sizeof(struct copy));
    > b = malloc(sizeof(struct copy));
    >
    > >
    > > if (a == NULL || b == NULL) {
    > > puts("malloc problem");
    > > exit(EXIT_FAILURE);
    > > }
    > > strcpy(b, "123456789");
    > > *(struct copy *)a = *(struct copy *)b; free(b); puts(a); free(a);
    > > return 0;
    > > }
    > > }
    > > /* END new.c */
    Suman, Aug 5, 2005
    #6
  7. Eric Laberge

    Netocrat Guest

    On Thu, 04 Aug 2005 21:34:47 -0700, Suman wrote:
    > Netocrat wrote:
    >> On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote:

    <snip>
    >> > int main(void)
    >> > {

    >> void *a, b;

    >
    > Is this really what you want? Typo, I presume. So, we'll change it
    > to...
    > void *a, *b;


    Yep, typo, well caught.
    Netocrat, Aug 5, 2005
    #7
  8. On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

    > Hi!
    >
    > I'm working on automatically generated code, and need to assign arrays.
    > memcpy is an obvious solution, but it becomes complicated to use in the
    > context I'm working on, ie.: I could use it but I don't want to.


    It is difficult to see how it would be more complicated than what you have
    here.

    > Arrays cannot be assigned in C, but structs can, so I coded the
    > following:
    >
    > #include <stdlib.h>
    >
    > int main(void)
    > {
    > void* a = malloc(10); /* This obviously should be checked for malloc
    > failure */
    > void* b = malloc(10); /* This too... */
    >
    > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);


    memcpy(a, b, 10);

    > free(a);
    > free(b);
    > return 0;
    > }
    >
    > I wouldn't have tought that this would compile, let alone not give a
    > single warning (gcc -W -Wall -pedantic). It even works :), as I tried
    > copying and displaying a string. I can easily code that in my code
    > generator (a translator, actually) and I suppose it would even let me
    > cast expressions to an array!


    You can't cast to an array type.

    > What I'm wondering, since this is not too bad looking as a solution,
    > is:
    > 1) Is this solution common?


    Not in my experience. :)

    > 2) Is this portable?


    It probably works on a wide range of implementations.

    > 3) Does this actually respects the C standard? (if not, why?)


    You're trying to access an array as a structure which ultimately has
    undefined behaviour. The fact that malloc'd memory is used muddies the
    water a bit especially in C90. But C99's concept of effective type makes
    it clearer.

    > 4) Any way to improve this assign without using a function?
    >
    > FYI, I tried using anonymous structures:
    > *((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
    > t[10];}*) b);
    > but the compiler complained about incompatible types, which I
    > understand the cause. I had to try it, though.


    What's the problem with using memcpy()?

    Lawrence
    Lawrence Kirby, Aug 5, 2005
    #8
  9. Eric Laberge

    Joe Wright Guest

    Lawrence Kirby wrote:
    > On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    >
    >
    >>Hi!
    >>
    >>I'm working on automatically generated code, and need to assign arrays.
    >>memcpy is an obvious solution, but it becomes complicated to use in the
    >>context I'm working on, ie.: I could use it but I don't want to.

    >
    >
    > It is difficult to see how it would be more complicated than what you have
    > here.
    >
    >
    >>Arrays cannot be assigned in C, but structs can, so I coded the
    >>following:
    >>
    >>#include <stdlib.h>
    >>
    >>int main(void)
    >>{
    >> void* a = malloc(10); /* This obviously should be checked for malloc
    >>failure */
    >> void* b = malloc(10); /* This too... */
    >>
    >> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

    >
    >
    > memcpy(a, b, 10);
    >
    >
    >> free(a);
    >> free(b);
    >> return 0;
    >>}
    >>
    >>I wouldn't have tought that this would compile, let alone not give a
    >>single warning (gcc -W -Wall -pedantic). It even works :), as I tried
    >>copying and displaying a string. I can easily code that in my code
    >>generator (a translator, actually) and I suppose it would even let me
    >>cast expressions to an array!

    >
    >
    > You can't cast to an array type.
    >
    >
    >>What I'm wondering, since this is not too bad looking as a solution,
    >>is:
    >>1) Is this solution common?

    >
    >
    > Not in my experience. :)
    >
    >
    >>2) Is this portable?

    >
    >
    > It probably works on a wide range of implementations.
    >
    >
    >>3) Does this actually respects the C standard? (if not, why?)

    >
    >
    > You're trying to access an array as a structure which ultimately has
    > undefined behaviour. The fact that malloc'd memory is used muddies the
    > water a bit especially in C90. But C99's concept of effective type makes
    > it clearer.
    >
    >
    >>4) Any way to improve this assign without using a function?
    >>
    >>FYI, I tried using anonymous structures:
    >>*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
    >>t[10];}*) b);
    >>but the compiler complained about incompatible types, which I
    >>understand the cause. I had to try it, though.

    >
    >
    > What's the problem with using memcpy()?
    >
    > Lawrence

    /* Assign array via struct */

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    #define LEN 20

    typedef struct {
    char a[LEN];
    } S;

    int main(void) {
    S sa;
    char A[LEN];

    S *ps = malloc(LEN);
    char *pa = malloc(LEN);

    strcpy(sa.a, "Joe Wright Rocks");
    puts(sa.a);

    *(S*)A = sa;
    puts(A);

    strcpy(ps->a, A);
    puts(ps->a);

    *(S*)pa = *ps;
    puts(pa);

    return 0;
    }

    I love this language. :)

    --
    Joe Wright
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
    Joe Wright, Aug 5, 2005
    #9
  10. Eric Laberge

    Jack Klein Guest

    On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <>
    wrote in comp.lang.c:

    > Lawrence Kirby wrote:
    > > On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    > >
    > >
    > >>Hi!
    > >>
    > >>I'm working on automatically generated code, and need to assign arrays.
    > >>memcpy is an obvious solution, but it becomes complicated to use in the
    > >>context I'm working on, ie.: I could use it but I don't want to.

    > >
    > >
    > > It is difficult to see how it would be more complicated than what you have
    > > here.
    > >
    > >
    > >>Arrays cannot be assigned in C, but structs can, so I coded the
    > >>following:
    > >>
    > >>#include <stdlib.h>
    > >>
    > >>int main(void)
    > >>{
    > >> void* a = malloc(10); /* This obviously should be checked for malloc
    > >>failure */
    > >> void* b = malloc(10); /* This too... */
    > >>
    > >> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

    > >
    > >
    > > memcpy(a, b, 10);
    > >
    > >
    > >> free(a);
    > >> free(b);
    > >> return 0;
    > >>}
    > >>
    > >>I wouldn't have tought that this would compile, let alone not give a
    > >>single warning (gcc -W -Wall -pedantic). It even works :), as I tried
    > >>copying and displaying a string. I can easily code that in my code
    > >>generator (a translator, actually) and I suppose it would even let me
    > >>cast expressions to an array!

    > >
    > >
    > > You can't cast to an array type.
    > >
    > >
    > >>What I'm wondering, since this is not too bad looking as a solution,
    > >>is:
    > >>1) Is this solution common?

    > >
    > >
    > > Not in my experience. :)
    > >
    > >
    > >>2) Is this portable?

    > >
    > >
    > > It probably works on a wide range of implementations.
    > >
    > >
    > >>3) Does this actually respects the C standard? (if not, why?)

    > >
    > >
    > > You're trying to access an array as a structure which ultimately has
    > > undefined behaviour. The fact that malloc'd memory is used muddies the
    > > water a bit especially in C90. But C99's concept of effective type makes
    > > it clearer.
    > >
    > >
    > >>4) Any way to improve this assign without using a function?
    > >>
    > >>FYI, I tried using anonymous structures:
    > >>*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
    > >>t[10];}*) b);
    > >>but the compiler complained about incompatible types, which I
    > >>understand the cause. I had to try it, though.

    > >
    > >
    > > What's the problem with using memcpy()?
    > >
    > > Lawrence

    > /* Assign array via struct */
    >
    > #include <stdio.h>
    > #include <string.h>
    > #include <stdlib.h>
    >
    > #define LEN 20
    >
    > typedef struct {
    > char a[LEN];
    > } S;
    >
    > int main(void) {
    > S sa;
    > char A[LEN];
    >
    > S *ps = malloc(LEN);
    > char *pa = malloc(LEN);
    >
    > strcpy(sa.a, "Joe Wright Rocks");
    > puts(sa.a);
    >
    > *(S*)A = sa;


    Here is where you invoke undefined behavior, since A isn't dynamically
    allocated. There is no guarantee that A meets the alignment
    requirements for an S. The compiler might generate code that assumes
    that A is, causing some sort of trap on some platforms, or possible
    misaligned data or overwriting the destination array.

    > puts(A);
    >
    > strcpy(ps->a, A);
    > puts(ps->a);
    >
    > *(S*)pa = *ps;
    > puts(pa);
    >
    > return 0;
    > }
    >
    > I love this language. :)


    I strongly dislike people who write code like this. Especially if I
    have to clean up after the 'clever' programmer. It would never pass a
    code inspection at any shop with decent standards. Shops that don't
    do code inspections don't have decent standards by definition.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Aug 6, 2005
    #10
  11. Jack Klein wrote:
    <snip>
    > > /* Assign array via struct */
    > >
    > > #include <stdio.h>
    > > #include <string.h>
    > > #include <stdlib.h>
    > >
    > > #define LEN 20
    > >
    > > typedef struct {
    > > char a[LEN];
    > > } S;
    > >
    > > int main(void) {
    > > S sa;
    > > char A[LEN];
    > >
    > > S *ps = malloc(LEN);
    > > char *pa = malloc(LEN);
    > >
    > > strcpy(sa.a, "Joe Wright Rocks");
    > > puts(sa.a);
    > >
    > > *(S*)A = sa;

    >
    > Here is where you invoke undefined behavior, since A isn't dynamically
    > allocated. There is no guarantee that A meets the alignment
    > requirements for an S. The compiler might generate code that assumes


    Even if A is dynamically allocated, e.g. variable 'pa', does standard
    guarantee that A is suitably aligned for struct S?
    may I have C&V for that?

    Krishanu
    Krishanu Debnath, Aug 6, 2005
    #11
  12. Netocrat wrote:

    <snip>

    >
    > > Even if A is dynamically allocated, e.g. variable 'pa', does standard
    > > guarantee that A is suitably aligned for struct S?

    >
    > It does. From the C89 draft (ANSI numbering):
    >
    > 4.10.3 Memory management functions
    >
    > The pointer returned [by the calloc , malloc , and realloc functions] if
    > the allocation succeeds is suitably aligned so that it may be assigned to
    > a pointer to any type of object and then used to access such an object in
    > the space allocated ...
    >
    > > may I have C&V for that?

    >
    > There is no constraint violation if that's what you mean.


    This is exactly I am looking for, thanks.

    Krishanu
    Krishanu Debnath, Aug 6, 2005
    #12
  13. Eric Laberge

    Netocrat Guest

    On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:

    >
    > Jack Klein wrote:
    > <snip>
    >> > /* Assign array via struct */
    >> >
    >> > #include <stdio.h>
    >> > #include <string.h>
    >> > #include <stdlib.h>
    >> >
    >> > #define LEN 20
    >> >
    >> > typedef struct {
    >> > char a[LEN];
    >> > } S;
    >> >
    >> > int main(void) {
    >> > S sa;
    >> > char A[LEN];
    >> >
    >> > S *ps = malloc(LEN);


    It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
    to use sizeof(S) than LEN.

    >> > char *pa = malloc(LEN);
    >> >
    >> > strcpy(sa.a, "Joe Wright Rocks");
    >> > puts(sa.a);
    >> >
    >> > *(S*)A = sa;


    Here you are potentially copying and assigning more than the allocated
    (to src and dest) LEN bytes. A compiler might do this for performance
    reasons. It's probably unlikely and a little pedantic but the point is
    that what you're doing isn't guaranteed safe by the standard.

    >>
    >> Here is where you invoke undefined behavior, since A isn't dynamically
    >> allocated. There is no guarantee that A meets the alignment
    >> requirements for an S. The compiler might generate code that assumes


    Given that element a must be located at the start of struct S, and that it
    is a char array of size LEN, it's hard to see how it could be aligned
    differently to the char array A of size LEN. Are you referring to this
    specific case or in general? If this case, could you explain how the
    standard allows the alignments to be different?

    > Even if A is dynamically allocated, e.g. variable 'pa', does standard
    > guarantee that A is suitably aligned for struct S?


    It does. From the C89 draft (ANSI numbering):

    4.10.3 Memory management functions

    The pointer returned [by the calloc , malloc , and realloc functions] if
    the allocation succeeds is suitably aligned so that it may be assigned to
    a pointer to any type of object and then used to access such an object in
    the space allocated ...

    > may I have C&V for that?


    There is no constraint violation if that's what you mean.

    --
    No longer posting under real email address
    (because that'll remove it from the spammers' databases)
    Remove the first word of the domain to re-construct it.
    Netocrat, Aug 6, 2005
    #13
  14. Eric Laberge

    Joe Wright Guest

    Jack Klein wrote:
    > On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <>
    > wrote in comp.lang.c:
    >
    >
    >>Lawrence Kirby wrote:
    >>
    >>>On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
    >>>
    >>>
    >>>
    >>>>Hi!
    >>>>
    >>>>I'm working on automatically generated code, and need to assign arrays.
    >>>>memcpy is an obvious solution, but it becomes complicated to use in the
    >>>>context I'm working on, ie.: I could use it but I don't want to.
    >>>
    >>>
    >>>It is difficult to see how it would be more complicated than what you have
    >>>here.
    >>>
    >>>
    >>>
    >>>>Arrays cannot be assigned in C, but structs can, so I coded the
    >>>>following:
    >>>>
    >>>>#include <stdlib.h>
    >>>>
    >>>>int main(void)
    >>>>{
    >>>> void* a = malloc(10); /* This obviously should be checked for malloc
    >>>>failure */
    >>>> void* b = malloc(10); /* This too... */
    >>>>
    >>>> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    >>>
    >>>
    >>> memcpy(a, b, 10);
    >>>
    >>>
    >>>
    >>>> free(a);
    >>>> free(b);
    >>>> return 0;
    >>>>}
    >>>>
    >>>>I wouldn't have tought that this would compile, let alone not give a
    >>>>single warning (gcc -W -Wall -pedantic). It even works :), as I tried
    >>>>copying and displaying a string. I can easily code that in my code
    >>>>generator (a translator, actually) and I suppose it would even let me
    >>>>cast expressions to an array!
    >>>
    >>>
    >>>You can't cast to an array type.
    >>>
    >>>
    >>>
    >>>>What I'm wondering, since this is not too bad looking as a solution,
    >>>>is:
    >>>>1) Is this solution common?
    >>>
    >>>
    >>>Not in my experience. :)
    >>>
    >>>
    >>>
    >>>>2) Is this portable?
    >>>
    >>>
    >>>It probably works on a wide range of implementations.
    >>>
    >>>
    >>>
    >>>>3) Does this actually respects the C standard? (if not, why?)
    >>>
    >>>
    >>>You're trying to access an array as a structure which ultimately has
    >>>undefined behaviour. The fact that malloc'd memory is used muddies the
    >>>water a bit especially in C90. But C99's concept of effective type makes
    >>>it clearer.
    >>>
    >>>
    >>>
    >>>>4) Any way to improve this assign without using a function?
    >>>>
    >>>>FYI, I tried using anonymous structures:
    >>>>*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
    >>>>t[10];}*) b);
    >>>>but the compiler complained about incompatible types, which I
    >>>>understand the cause. I had to try it, though.
    >>>
    >>>
    >>>What's the problem with using memcpy()?
    >>>
    >>>Lawrence

    >>
    >>/* Assign array via struct */
    >>
    >>#include <stdio.h>
    >>#include <string.h>
    >>#include <stdlib.h>
    >>
    >>#define LEN 20
    >>
    >>typedef struct {
    >> char a[LEN];
    >>} S;
    >>
    >>int main(void) {
    >> S sa;
    >> char A[LEN];
    >>
    >> S *ps = malloc(LEN);
    >> char *pa = malloc(LEN);
    >>
    >> strcpy(sa.a, "Joe Wright Rocks");
    >> puts(sa.a);
    >>
    >> *(S*)A = sa;

    >
    >
    > Here is where you invoke undefined behavior, since A isn't dynamically
    > allocated. There is no guarantee that A meets the alignment
    > requirements for an S. The compiler might generate code that assumes
    > that A is, causing some sort of trap on some platforms, or possible
    > misaligned data or overwriting the destination array.
    >

    All of S is an array of char. What alignment requirements might there be
    for an S? None. Structures don't have alignment requirements, their
    members do. What are the alignment requirements of a char array?
    >
    >> puts(A);
    >>
    >> strcpy(ps->a, A);
    >> puts(ps->a);
    >>
    >> *(S*)pa = *ps;
    >> puts(pa);
    >>
    >> return 0;
    >>}
    >>
    >>I love this language. :)

    >
    >
    > I strongly dislike people who write code like this. Especially if I
    > have to clean up after the 'clever' programmer. It would never pass a
    > code inspection at any shop with decent standards. Shops that don't
    > do code inspections don't have decent standards by definition.
    >

    You 'strongly dislike people' who try to get 'clever' with C in a
    newsgroup posting? Boy, are you tough.

    I thought you'd get me for not checking the malloc() returns and not
    free()ing ps and pa before exit. You never know your luck.

    --
    Joe Wright
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
    Joe Wright, Aug 6, 2005
    #14
  15. Eric Laberge

    Joe Wright Guest

    Netocrat wrote:
    > On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
    >
    >
    >>Jack Klein wrote:
    >><snip>
    >>
    >>>>/* Assign array via struct */
    >>>>
    >>>>#include <stdio.h>
    >>>>#include <string.h>
    >>>>#include <stdlib.h>
    >>>>
    >>>>#define LEN 20
    >>>>
    >>>>typedef struct {
    >>>> char a[LEN];
    >>>>} S;
    >>>>
    >>>>int main(void) {
    >>>> S sa;
    >>>> char A[LEN];
    >>>>
    >>>> S *ps = malloc(LEN);

    >
    >
    > It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
    > to use sizeof(S) than LEN.
    >

    What padding could there be? S is essentially a char array.
    >
    >>>> char *pa = malloc(LEN);
    >>>>
    >>>> strcpy(sa.a, "Joe Wright Rocks");
    >>>> puts(sa.a);
    >>>>
    >>>> *(S*)A = sa;

    >
    >
    > Here you are potentially copying and assigning more than the allocated
    > (to src and dest) LEN bytes. A compiler might do this for performance
    > reasons. It's probably unlikely and a little pedantic but the point is
    > that what you're doing isn't guaranteed safe by the standard.
    >

    You're assuming sizeof sa might be greater than LEN. Why?
    >
    >>>Here is where you invoke undefined behavior, since A isn't dynamically
    >>>allocated. There is no guarantee that A meets the alignment
    >>>requirements for an S. The compiler might generate code that assumes

    >
    >
    > Given that element a must be located at the start of struct S, and that it
    > is a char array of size LEN, it's hard to see how it could be aligned
    > differently to the char array A of size LEN. Are you referring to this
    > specific case or in general? If this case, could you explain how the
    > standard allows the alignments to be different?
    >

    Now you are on my side. Welcome home.
    >
    >>Even if A is dynamically allocated, e.g. variable 'pa', does standard
    >>guarantee that A is suitably aligned for struct S?

    >
    >
    > It does. From the C89 draft (ANSI numbering):
    >
    > 4.10.3 Memory management functions
    >
    > The pointer returned [by the calloc , malloc , and realloc functions] if
    > the allocation succeeds is suitably aligned so that it may be assigned to
    > a pointer to any type of object and then used to access such an object in
    > the space allocated ...
    >
    >
    >>may I have C&V for that?

    >
    >
    > There is no constraint violation if that's what you mean.
    >



    --
    Joe Wright
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
    Joe Wright, Aug 6, 2005
    #15
  16. Eric Laberge

    Netocrat Guest

    On Sat, 06 Aug 2005 08:45:05 -0400, Joe Wright wrote:
    > Netocrat wrote:
    >> On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
    >>>Jack Klein wrote:
    >>><snip>
    >>>
    >>>>>/* Assign array via struct */
    >>>>>
    >>>>>#include <stdio.h>
    >>>>>#include <string.h>
    >>>>>#include <stdlib.h>
    >>>>>
    >>>>>#define LEN 20
    >>>>>
    >>>>>typedef struct {
    >>>>> char a[LEN];
    >>>>>} S;
    >>>>>
    >>>>>int main(void) {
    >>>>> S sa;
    >>>>> char A[LEN];
    >>>>>
    >>>>> S *ps = malloc(LEN);

    >>
    >>
    >> It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
    >> to use sizeof(S) than LEN.
    >>

    > What padding could there be? S is essentially a char array.


    Yeah, that's why I called it a pedantic point later in the post. Probably
    the DS9000 is the only implementation to include padding. Anyhow you lose
    nothing by using sizeof(S) instead of LEN and you are assured of
    compliance.

    >>>>> char *pa = malloc(LEN);
    >>>>>
    >>>>> strcpy(sa.a, "Joe Wright Rocks");
    >>>>> puts(sa.a...);
    >>>>>
    >>>>> *(S*)A = sa;

    >>
    >>
    >> Here you are potentially copying and assigning more than the allocated
    >> (to src and dest) LEN bytes. A compiler might do this for performance
    >> reasons. It's probably unlikely and a little pedantic but the point is
    >> that what you're doing isn't guaranteed safe by the standard.
    >>

    > You're assuming sizeof sa might be greater than LEN. Why?


    As above - padding. I wrote that it might be added for performance
    reasons. I don't know if such reasons legitimately exist on a real-world
    implementation (I can contrive a far-fetched hypothetical implementation
    where they do), but you never know what code an optimising compiler is
    going to generate.

    <snip rest>
    Netocrat, Aug 6, 2005
    #16
  17. Eric Laberge

    S.Tobias Guest

    Lawrence Kirby <> wrote:
    > On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:


    [snip]
    >> #include <stdlib.h>
    >>
    >> int main(void)
    >> {
    >> void* a = malloc(10); /* This obviously should be checked for malloc
    >> failure */
    >> void* b = malloc(10); /* This too... */
    >>
    >> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

    >
    > memcpy(a, b, 10);
    >
    >> free(a);
    >> free(b);
    >> return 0;
    >> }


    [snip]
    >> 3) Does this actually respects the C standard? (if not, why?)

    >
    > You're trying to access an array as a structure which ultimately has
    > undefined behaviour. The fact that malloc'd memory is used muddies the
    > water a bit especially in C90. But C99's concept of effective type makes
    > it clearer.


    Taking size and allignment issues away, I thing the array (supposing
    it is an array type object already) *could* be accessed through
    the struct type:

    n869.txt, 6.5#7:
    # [#7] An object shall have its stored value accessed only by
    # an lvalue expression that has one of the following types:63)
    [...]
    # -- an aggregate or union type that includes one of the
    # aforementioned types among its members (including,
    # recursively, a member of a subaggregate or contained
    # union), or

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
    S.Tobias, Aug 6, 2005
    #17
  18. Eric Laberge

    S.Tobias Guest

    Netocrat <> wrote:
    > On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
    >> Jack Klein wrote:


    >> <snip>
    >>> > /* Assign array via struct */
    >>> >
    >>> > #include <stdio.h>
    >>> > #include <string.h>
    >>> > #include <stdlib.h>
    >>> >
    >>> > #define LEN 20
    >>> >
    >>> > typedef struct {
    >>> > char a[LEN];
    >>> > } S;
    >>> >
    >>> > int main(void) {
    >>> > S sa;
    >>> > char A[LEN];
    >>> >
    >>> > S *ps = malloc(LEN);

    >
    > It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
    > to use sizeof(S) than LEN.
    >
    >>> > char *pa = malloc(LEN);
    >>> >
    >>> > strcpy(sa.a, "Joe Wright Rocks");
    >>> > puts(sa.a);
    >>> >
    >>> > *(S*)A = sa;

    [snip]
    >>> Here is where you invoke undefined behavior, since A isn't dynamically
    >>> allocated. There is no guarantee that A meets the alignment
    >>> requirements for an S. The compiler might generate code that assumes

    >
    > Given that element a must be located at the start of struct S, and that it
    > is a char array of size LEN, it's hard to see how it could be aligned
    > differently to the char array A of size LEN. Are you referring to this
    > specific case or in general? If this case, could you explain how the
    > standard allows the alignments to be different?


    Type `char' has no alignment (ie. alignment(char) == 1), of course,
    but at issue is not `char', but rather `char[10]'. Long time ago
    (don't ask me for details now) I read that on DEC stations character
    arrays in structs could have different alignments depending on their
    size, so for example `char[15]' could have different alignment than
    `char[31]'. All this was for purpose of memory access speed; ordinarily
    `char[ANY]' doesn't have alignment (at least when ANY is a prime number,
    for others I don't know), but when in a struct, a compiler
    could assume that the array is positioned at a "fast" location and
    generate more optimal code. (BTW, the discussion in which I read it
    was about why struct-hack didn't work.)

    I think that does it for an explanation of the struct alignment and
    padding (later in this thread).


    [snip]
    >> may I have C&V for that?

    >
    > There is no constraint violation if that's what you mean.


    He meant "Chapter & Verse". :-D

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
    S.Tobias, Aug 6, 2005
    #18
  19. Eric Laberge

    Tim Rentsch Guest

    "Eric Laberge" <> writes:

    > Hi!
    >
    > I'm working on automatically generated code, and need to assign arrays.
    > memcpy is an obvious solution, but it becomes complicated to use in the
    > context I'm working on, ie.: I could use it but I don't want to.
    > Arrays cannot be assigned in C, but structs can, so I coded the
    > following:
    >
    > #include <stdlib.h>
    >
    > int main(void)
    > {
    > void* a = malloc(10); /* This obviously should be checked for malloc
    > failure */
    > void* b = malloc(10); /* This too... */
    >
    > *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
    >
    > free(a);
    > free(b);
    > return 0;
    > }


    Perhaps it would be easier have the variables be
    the assignable type to begin with:

    #include <stdlib.h>

    typedef struct { char v[10]; } SC_10;

    int main(void)
    {
    SC_10 *a = malloc( sizeof *a );
    SC_10 *b = malloc( sizeof *b );

    if( !a || !b ){ ... }

    sprintf( b->v, "Hi there\n" ); /* array use */

    *a = *b; /* assignment use */

    free(a);
    free(b);
    return 0;
    }

    No questionable behavior, and no casting necessary.

    The type could be a union rather than a struct if
    the "wrapped" value needs to be accessed as some
    other type(s) in addition to being accessed as a
    character array or unsigned character array.

    If you can, it's almost always better to write
    code so it doesn't need casts -- even code that
    is automatically generated.
    Tim Rentsch, Aug 6, 2005
    #19
  20. Eric Laberge

    Tim Rentsch Guest

    Joe Wright <> writes:

    > All of S is an array of char. What alignment requirements
    > might there be for an S? None. Structures don't have
    > alignment requirements, their members do. What are the
    > alignment requirements of a char array?


    Structures can have alignment requirements that
    are different from those of their members, and
    here's a possible reason why they would.

    On platforms where a 'char *' is a different
    format and/or wider than an 'int *', an
    implementation might choose to make all structs
    be 'int' aligned, so that structure pointers
    would be easier to deal with.

    So a structure holding a character array would
    still need 'int' alignment, even though the
    contained character array would need only 'char'
    alignment.

    The alignment requirement also implies a sizing
    requirement, since alignment_of(T) must evenly
    divide 'sizeof(T)'. That's why a struct that
    holds only a character array might be bigger
    than the character array it holds.
    Tim Rentsch, Aug 6, 2005
    #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. Chris Fogelklou
    Replies:
    36
    Views:
    1,369
    Chris Fogelklou
    Apr 20, 2004
  2. Matthias Kaeppler
    Replies:
    2
    Views:
    437
    Victor Bazarov
    Jul 18, 2005
  3. Noob
    Replies:
    25
    Views:
    1,463
    Nick Keighley
    Dec 9, 2009
  4. Tuan  Bui
    Replies:
    14
    Views:
    470
    it_says_BALLS_on_your forehead
    Jul 29, 2005
  5. nelson331
    Replies:
    3
    Views:
    546
    A. Sinan Unur
    Apr 29, 2006
Loading...

Share This Page