Stupid cast question

Discussion in 'C Programming' started by Dopey, Aug 13, 2003.

  1. Dopey

    Dopey Guest

    This is not homework.

    I'm trying to understand why this code doesn't output "$$$$$$$\0\n"
    -- all I get is "$)\n". (I admit I'm an idiot, OK?)

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

    struct mystruct
    {
    int a, b, c, d, e, f, g ;
    } ;

    int
    main(void)
    {
    int i ;
    struct mystruct * ms = malloc( sizeof(struct mystruct) ) ;
    unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;

    ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$' ;

    for ( i = 0; i < sizeof( ms ) ; i++ )
    buf = (unsigned char)*((unsigned char *)&ms) ;

    buf = '\0' ;

    printf( "%s\n", buf ) ;

    return 0 ;
    }
     
    Dopey, Aug 13, 2003
    #1
    1. Advertising

  2. Dopey

    Dan Pop Guest

    In <> Dopey <> writes:

    >This is not homework.
    >
    >I'm trying to understand why this code doesn't output "$$$$$$$\0\n"


    It was a good idea that you posted the expected output, because the
    program is completely meaningless and we couldn't figure out how to fix
    it without this piece of information.

    >-- all I get is "$)\n". (I admit I'm an idiot, OK?)


    OK ;-)

    >#include <stdio.h>
    >#include <stdlib.h>
    >
    >struct mystruct
    >{
    > int a, b, c, d, e, f, g ;
    >} ;
    >
    >int
    >main(void)
    >{
    > int i ;
    > struct mystruct * ms = malloc( sizeof(struct mystruct) ) ;
    > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;


    The size of the buffer is incorrectly calculated: you want one byte for
    each member of the struct plus one byte for the string terminator.
    Assuming a non-perverse implementation, you can obtain the number of
    struct members (in this particular case) with the following expression:

    sizeof *ms / sizeof ms -> a

    or

    sizeof(struct mystruct) / sizeof(int)

    The former may look more cryptical, but it doesn't require any
    maintenance if you decide to change the name of the struct or the type
    of its members later.

    So, the correct allocation for buf is:

    unsigned char * buf = malloc((sizeof *ms / sizeof ms -> a) + 1 ) ;

    > ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$' ;
    >
    > for ( i = 0; i < sizeof( ms ) ; i++ )


    You got the iteration count horribly wrong: sizeof ms is giving you the
    size of a pointer to a structure, which is completely unrelated to the
    number of members of the struct. You need exactly the same expression
    as above:

    for (i = 0; i < sizeof *ms / sizeof ms -> a; i++)

    > buf = (unsigned char)*((unsigned char *)&ms) ;


    This is a horrible mess. You have allocated memory for a single
    struct, not for a whole array of them. What you need is to convert ms
    to pointer to int and use that pointer for accessing each member of
    the struct, as if you had an array of int's:

    buf = ((int *)ms) ;

    As you can see, the correct expression is much simpler than your bit of
    nonsense.

    > buf = '\0' ;
    >
    > printf( "%s\n", buf ) ;
    >
    > return 0 ;
    >}


    Now, let's see what we've got:

    fangorn:~/tmp 2493> cat test.c
    #include <stdio.h>
    #include <stdlib.h>

    struct mystruct
    {
    int a, b, c, d, e, f, g ;
    };

    int main(void)
    {
    int i;
    struct mystruct *ms = malloc(sizeof(struct mystruct));
    char *buf = malloc((sizeof *ms / sizeof ms -> a) + 1);

    ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$';
    for (i = 0; i < sizeof *ms / sizeof ms -> a; i++)
    buf = ((int *)ms);
    buf = '\0';
    printf("%s\n", buf);
    return 0 ;
    }
    fangorn:~/tmp 2494> gcc -ansi -pedantic test.c
    fangorn:~/tmp 2495> ./a.out
    $$$$$$$

    It looks like the expected output. But the program still relies on the
    reasonable assumption that struct mystruct contains no padding at all.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
     
    Dan Pop, Aug 13, 2003
    #2
    1. Advertising

  3. Dopey

    -berlin.de Guest

    Dopey <> wrote:
    > This is not homework.


    > I'm trying to understand why this code doesn't output "$$$$$$$\0\n"
    > -- all I get is "$)\n". (I admit I'm an idiot, OK?)


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


    > struct mystruct
    > {
    > int a, b, c, d, e, f, g ;
    > } ;


    > int
    > main(void)
    > {
    > int i ;
    > struct mystruct * ms = malloc( sizeof(struct mystruct) ) ;
    > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;


    Shouldn't you check that ms and buf aren't NULL?

    >
    > ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$' ;
    >
    > for ( i = 0; i < sizeof( ms ) ; i++ )


    sizeof(ms) returns the size of the pointer, not the length of what
    it points to. Use either "sizeof *ms" or sizeof(struct mystruct).

    > buf = (unsigned char)*((unsigned char *)&ms) ;


    ms isn't an array, but a pointer to a single structure (that's all
    you allocated). Since you obviously try to print out the structure
    in a byte by byte fashion you probably need

    buf = * ( ( unsigned char * ) msg + i );

    to step over the memory pointed to by ms in a byte-by-byte way.

    >
    > buf = '\0' ;
    >
    > printf( "%s\n", buf ) ;


    This still won't print out "$$$$$$$\0\n". First of all '\0' isn't a
    printable character, it indicates the end of the string. Second,
    the members of your mystruct are all ints, and since the size of an
    int is usually larger than the one of a char you will have additional
    (zero) bytes in between the '$'s (not even counting possible padding
    bytes). The moment the printf() function finds one of the zero bytes
    it will stop printing.

    > return 0 ;
    > }

    Regards, Jens
    --
    _ _____ _____
    | ||_ _||_ _| -berlin.de
    _ | | | | | |
    | |_| | | | | | http://www.physik.fu-berlin.de/~toerring
    \___/ens|_|homs|_|oerring
     
    -berlin.de, Aug 13, 2003
    #3
  4. Dopey

    Dopey Guest

    -berlin.de wrote...
    > Dopey <> wrote:
    > > This is not homework.

    >
    > > I'm trying to understand why this code doesn't output "$$$$$$$\0\n"
    > > -- all I get is "$)\n". (I admit I'm an idiot, OK?)

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

    >
    > > struct mystruct
    > > {
    > > int a, b, c, d, e, f, g ;
    > > } ;

    >
    > > int
    > > main(void)
    > > {
    > > int i ;
    > > struct mystruct * ms = malloc( sizeof(struct mystruct) ) ;
    > > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;

    >
    > Shouldn't you check that ms and buf aren't NULL?


    There's quite enough to criticize in the code without dinging me for
    leaving the error checking out of the example I posted to illustrate
    the problem.
     
    Dopey, Aug 13, 2003
    #4
  5. Dopey

    goose Guest

    Dopey <> wrote in message news:<>...
    > This is not homework.


    even if it was, giving it a try before asking for help
    is the accepted way of doing things.

    <grin> its a good thing you follow accepted ways !

    >
    > I'm trying to understand why this code doesn't output "$$$$$$$\0\n"
    > -- all I get is "$)\n". (I admit I'm an idiot, OK?)


    great, that'll save Dan Pop the effort of admitting that you
    are an idiot :)

    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > struct mystruct
    > {
    > int a, b, c, d, e, f, g ;
    > } ;
    >
    > int
    > main(void)
    > {
    > int i ;
    > struct mystruct * ms = malloc( sizeof(struct mystruct) ) ; >...
    > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;
    > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;


    at this point, it is generally a good idea to check
    that malloc returned a non-null pointer. what if the
    system was out of memory ?

    > ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$' ;
    > ms->a = ms->b = ms->c = ms->d = ms->e = ms->f = ms->g = '$' ;
    > for ( i = 0; i < sizeof( ms ) ; i++ )


    sizeof ( ms ) would be the size of a *pointer* to your struct.
    to get the size of the actual object, you should use
    sizeof (*ms);

    > buf = (unsigned char)*((unsigned char *)&ms) ;


    ms is *not* an array. it is a pointer to a single struct. I understand
    what you are aiming for (i must, after all you posted the expected
    output above :), but I would recommend that you access each member
    of a struct individually. the reason is because the compiler *may*
    pad the struct, and accessing the struct as one block of memory is
    bound to end in tears sooner or later, as you find 'gaps' in your
    block of data would be filled with garbage.

    > uld be filled with garbage.
    > buf = '\0' ;
    > '\0' ;
    > printf( "%s\n", buf ) ;


    even if your compiler did not pad the structure, this can still
    fail if sizeof (int) != sizeof (char), as printf ("%s\n", buf)
    needs an array of chars, not an array of integers.

    >
    > return 0 ;
    > }


    hth

    goose,
    outlaw the non sc apps. makes life easier for *evryone* :)
     
    goose, Aug 13, 2003
    #5
  6. Dopey

    pete Guest

    Dopey wrote:
    >
    > -berlin.de wrote...
    > > Dopey <> wrote:
    > > > This is not homework.

    > >
    > > > I'm trying to understand why this code doesn't output "$$$$$$$\0\n"
    > > > -- all I get is "$)\n". (I admit I'm an idiot, OK?)

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

    > >
    > > > struct mystruct
    > > > {
    > > > int a, b, c, d, e, f, g ;
    > > > } ;

    > >
    > > > int
    > > > main(void)
    > > > {
    > > > int i ;
    > > > struct mystruct * ms = malloc( sizeof(struct mystruct) ) ;
    > > > unsigned char * buf = malloc( sizeof(struct mystruct) + 1 ) ;

    > >
    > > Shouldn't you check that ms and buf aren't NULL?

    >
    > There's quite enough to criticize in the code without dinging me for
    > leaving the error checking out of the example I posted to illustrate
    > the problem.


    It would have been less effort on your part
    to include error checking originally, than to answer.
    That you are personally aware that error checking belongs in the code,
    is good, but it is not all that matters.
    Your code is out there for all to see,
    and it is missing error checking.

    --
    pete
     
    pete, Aug 13, 2003
    #6
    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. Thomas Matthews

    Re: Next stupid cast question

    Thomas Matthews, Aug 13, 2003, in forum: C Programming
    Replies:
    2
    Views:
    419
    Mark McIntyre
    Aug 14, 2003
  2. goose

    Re: Next stupid cast question

    goose, Aug 14, 2003, in forum: C Programming
    Replies:
    0
    Views:
    377
    goose
    Aug 14, 2003
  3. EvilRix
    Replies:
    8
    Views:
    654
    Martin Dickopp
    Feb 14, 2004
  4. Brandon McCombs
    Replies:
    4
    Views:
    519
    Richard Wheeldon
    Aug 28, 2006
  5. rincewind

    stupid, STUPID question!

    rincewind, Apr 19, 2009, in forum: HTML
    Replies:
    25
    Views:
    1,026
Loading...

Share This Page