Initialization of struct to zero with a cast

Discussion in 'C Programming' started by Voyageur Galactique, Feb 10, 2011.

  1. Hi,

    Suppose I have a struct T .

    struct T* t = malloc(sizeof(struct T));

    I want to initialize t to zero.
     
    Voyageur Galactique, Feb 10, 2011
    #1
    1. Advertising

  2. Hi,

    Suppose I have a struct T .

    struct T* t = malloc(sizeof(struct T));

    I want to initialize t to zero.

    I did it in the following way :

    *t = (struct T) {0};

    I would like to know if it is safe ?
    From my experience, it works well with gcc, but is it guaranteed to
    work on other compiler ?

    Thanks
     
    Voyageur Galactique, Feb 10, 2011
    #2
    1. Advertising

  3. Voyageur Galactique

    David RF Guest

    On 10 feb, 10:51, Voyageur Galactique <>
    wrote:
    > Hi,
    >
    > Suppose I have a struct T .
    >
    > struct T* t = malloc(sizeof(struct T));
    >
    > I want to initialize t to zero.
    >
    > I did it in the following way :
    >
    > *t = (struct T) {0};
    >
    > I would like to know if it is safe ?
    > From my experience, it works well with gcc, but is it guaranteed to
    > work on other compiler ?
    >
    > Thanks


    http://www.ex-parrot.com/~chris/random/initialise.html
     
    David RF, Feb 10, 2011
    #3
  4. Thank you for pointing me this artcile.

    I answers one part of my question.

    If I well understand, the statement :
    struct T t = {0}
    will set the fist field to 0 and initialize other fields the same way
    it does for static storage.

    A practical example is the following :

    struct T t_init = {0}, *t = malloc(sizeof(struct T));
    *t = t_init;

    It is equivalent to :

    static struct T t_init;
    struct T* t = malloc(sizeof(struct T));
    *t = t_init;

    But what about the casting technique ?

    struct T* t = malloc(sizeof(struct T));
    *t = (struct T) {0};

    It works, but I'm not sure it should.


    On Feb 10, 11:51 am, David RF <> wrote:
    > On 10 feb, 10:51, Voyageur Galactique <>
    > wrote:
    >
    >
    >
    > > Hi,

    >
    > > Suppose I have a struct T .

    >
    > > struct T* t = malloc(sizeof(struct T));

    >
    > > I want to initialize t to zero.

    >
    > > I did it in the following way :

    >
    > > *t = (struct T) {0};

    >
    > > I would like to know if it is safe ?
    > > From my experience, it works well with gcc, but is it guaranteed to
    > > work on other compiler ?

    >
    > > Thanks

    >
    > http://www.ex-parrot.com/~chris/random/initialise.html
     
    Voyageur Galactique, Feb 10, 2011
    #4
  5. Voyageur Galactique <> writes:

    > Suppose I have a struct T .
    >
    > struct T* t = malloc(sizeof(struct T));
    >
    > I want to initialize t to zero.


    The page that someone else has pointed you to explains that "zero" is,
    sadly, slightly ambiguous in this context.

    > I did it in the following way :
    >
    > *t = (struct T) {0};
    >
    > I would like to know if it is safe ?


    Yes, that is absolutely safe. It will work even when a null pointer (or
    a floating point zero) is not all bits zero.

    > From my experience, it works well with gcc, but is it guaranteed to
    > work on other compiler ?


    The trouble is that it's C99 -- the newest C standard -- and not all
    compilers implement C99.

    --
    Ben.
     
    Ben Bacarisse, Feb 10, 2011
    #5
  6. Voyageur Galactique

    Tom St Denis Guest

    On Feb 10, 4:47 am, Voyageur Galactique
    <> wrote:
    > Hi,
    >
    > Suppose I have a struct T .
    >
    > struct T* t = malloc(sizeof(struct T));
    >
    > I want to initialize t to zero.


    use calloc instead?

    Tom
     
    Tom St Denis, Feb 10, 2011
    #6
  7. Voyageur Galactique <> writes:
    <snip>
    > But what about the casting technique ?
    >
    > struct T* t = malloc(sizeof(struct T));
    > *t = (struct T) {0};
    >
    > It works, but I'm not sure it should.


    For a conforming C99 compiler yes. Technically it's not a cast. The
    construct:

    (type-name){ initialisers }

    is called a compound literal. It's effect is to make an un-named object
    of the given type. A cast produces just a value whereas a compound
    literal is an object you can take the address of.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Feb 10, 2011
    #7
  8. Voyageur Galactique

    David RF Guest

    On 10 feb, 12:42, Voyageur Galactique <>
    wrote:

    > > > I want to initialize t to zero.

    >
    > > > I did it in the following way :

    >
    > > > *t = (struct T) {0};

    >
    > > > I would like to know if it is safe ?


    Yes, set all struct members to 0
     
    David RF, Feb 10, 2011
    #8
  9. > Technically it's not a cast. The construct:
    >
    > (type-name){ initialisers }
    >
    > is called a compound literal. It's effect is to make an un-named object
    > of the given type. A cast produces just a value whereas a compound
    > literal is an object you can take the address of.
    > --
    > Ben.


    Thank you, it completely answers my question.
    I'm very pleased to learn it's something else than a cast. I couldn't
    understand how it could ever work.
     
    Voyageur Galactique, Feb 10, 2011
    #9
  10. > > struct T* t = malloc(sizeof(struct T));
    >
    > > I want to initialize t to zero.

    >
    > use calloc instead?
    >
    > Tom


    Of course not. My question was misleading. I wanted to say,
    "initialize *t to zero", or more precisely "intialize all fieds in t*
    struct to zero"
     
    Voyageur Galactique, Feb 10, 2011
    #10
  11. I thank you all for your instructive answers.

    Just a few pieces informations I found about compound literals
    regarding portability :

    - "C++ supports this feature as an extension to Standard C++ for
    compatibility with C"
    quoting :
    http://publib.boulder.ibm.com/infoc....doc/language/ref/clrc02compound_literals.htm

    - "As an extension, GCC supports compound literals in C90 mode and in C
    ++."
    quoting :
    http://gcc.gnu.org/onlinedocs/gcc-4.5.2/gcc/Compound-Literals.html

    - Chances are it is not supported in MSVC but I didn't tried.

    To finish, an alternate solution to add to my collection :
    found in :
    http://gcc.gnu.org/onlinedocs/gcc-4.5.2/gcc/Compound-Literals.html

    struct T* t = malloc(sizeof(struct T));
    {
    struct T temp = {0};
    *t = temp;
    }
     
    Voyageur Galactique, Feb 10, 2011
    #11
  12. Voyageur Galactique

    Tom St Denis Guest

    On Feb 10, 8:53 am, Voyageur Galactique
    <> wrote:
    > > > struct T* t = malloc(sizeof(struct T));

    >
    > > > I want to initialize t to zero.

    >
    > > use calloc instead?

    >
    > > Tom

    >
    > Of course not. My question was misleading. I wanted to say,
    > "initialize *t to zero", or more precisely "intialize all fieds in t*
    > struct to zero"


    memset(t, 0, sizeof *t);

    Tom
     
    Tom St Denis, Feb 10, 2011
    #12
  13. On Feb 10, 3:43 pm, Tom St Denis <> wrote:
    > On Feb 10, 8:53 am, Voyageur Galactique
    >
    > <> wrote:
    > > > > struct T* t = malloc(sizeof(struct T));

    >
    > > > > I want to initialize t to zero.

    >
    > > > use calloc instead?

    >
    > > > Tom

    >
    > > Of course not. My question was misleading. I wanted to say,
    > > "initialize *t to zero", or more precisely "intialize all fieds in t*
    > > struct to zero"

    >
    > memset(t, 0, sizeof *t);
    >
    > Tom


    You are right it works! But is it guaranted to work everytime
    everywhere? I what taught the bit representation didn't always reflect
    what appears to a 0 for the user.

    struct T {
    int _int;
    double _double;
    struct {
    char _char;
    float _float;
    } sub;
    };

    int main(void) {

    struct T* t = malloc(sizeof(struct T));
    memset(t, 0, sizeof(struct T));
    printf("%d, %f, %i, %f \n", t->_int, t->_double, t->sub._char, t-
    >sub._float);


    struct T* s = calloc(1, sizeof(struct T));
    printf("%d, %f, %i, %f \n", s->_int, s->_double, s->sub._char, s-
    >sub._float);

    }



    Are you it is supposed to work ?
     
    Voyageur Galactique, Feb 10, 2011
    #13
  14. Voyageur Galactique <> writes:
    >> > struct T* t = malloc(sizeof(struct T));

    >>
    >> > I want to initialize t to zero.

    >>
    >> use calloc instead?

    >
    > Of course not. My question was misleading. I wanted to say,
    > "initialize *t to zero", or more precisely "intialize all fieds in t*
    > struct to zero"


    Right, that's what calloc() does: it allocates space (as if by a
    call to malloc), sets that space to all-bits-zero, and returns a
    pointer to the newly allocated space. It's equivalent to calling
    malloc() followed by memset().

    But unless your struct T consists entirely of integer members
    (possibly nested within sub-structs and so forth), there's no
    guarantee that all-bits-zero is a representation of zero for
    the type. (The guarantee that all-bita-zero is a representation
    of zero for integer types didn't appear until after C99, in
    one of the Technical Corrigenda, but the committee felt free
    to add this guarantee because it was already satisfied by all
    (?) implementations.)

    (And you're checking the result of malloc(), right?)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Feb 10, 2011
    #14
  15. > (And you're checking the result of malloc(), right?)

    Yes. Actually I want to dynamically allocate memory for pointers
    contained in a struct and I'm looking for an easy way to release all
    memory in case of malloc failure.
    I know it is a bit remote with the starting topic of this thread, but
    here is an example :
    Please leave me your comments if you want.


    typedef struct Foo {
    char * pt_1;
    float * pt_2;
    int** pt_3;
    /* (...) a lot of pointers */
    int val_1;
    /* (...) a lot of variables */
    } Foo;

    void del_foo(Foo* t);

    Foo* new_foo()
    {
    int i;
    Foo* t = malloc(sizeof(Foo));
    if (!t) goto cleanup;
    *t = (Foo) {0};

    t->pt_1 = malloc(sizeof(char)*100);
    if (!t->pt_1) goto cleanup;

    t->pt_2 = malloc(sizeof(float));
    if (!t->pt_2) goto cleanup;

    t->pt_3 = calloc(sizeof(int*), 42);
    if (!t->pt_3) goto cleanup;
    for(i = 0; i < 42; i++)
    {
    t->pt_3 = malloc(sizeof(int));
    if (!t->pt_3) goto cleanup;
    }

    /* (...) memory allocation for other pointers*/

    return t;

    cleanup:
    if (t) del_foo(t);
    return NULL;
    }

    void del_foo(Foo* t)
    {
    int i;
    free(t->pt_1);
    free(t->pt_2);
    if (t->pt_3) {
    for(i = 0; i < 42; i++)
    {
    free(t->pt_3);
    }
    }
    free(t->pt_3);

    /* (...) freeing memory allocation from other pointers*/

    free(t);
    }
     
    Voyageur Galactique, Feb 10, 2011
    #15
  16. Ah I forgot, regarding what was already said :

    the statement is not guaranted to work :
    t->pt_3 = calloc(sizeof(int*), 42);

    it should be replaced with :
    t->pt_3 = malloc(sizeof(int*) * 42);
    for(i = 0; i < 42; i++) {
    t->pt_3=NULL;
    }
     
    Voyageur Galactique, Feb 10, 2011
    #16
  17. On Feb 13, 8:29 am, (Richard Harter) wrote:
    > On Thu, 10 Feb 2011 08:40:03 -0800 (PST), Voyageur Galactique
    >
    > <> wrote:
    > >> (And you're checking the result of malloc(), right?)

    >
    > >Yes. Actually I want to dynamically allocate memory for pointers
    > >contained in a struct and I'm looking for an easy way to release all
    > >memory in case of malloc failure.
    > >I know it is a bit remote with the starting topic of this thread, but
    > >here is an example :
    > >Please leave me your comments if you want.

    >
    > [snip example]
    >
    > You might find it worh the effort to put together a little storage
    > management utility that I call a storage pool kit.  (No doubt there is
    > a better name.)
    >
    > The basic idea is to refine the world's simplest storage allocator. It
    > works like this:  We start with a block of unallocated storage and and
    > a pointer to the beginning of unallocated storage.  When we get a
    > request for storage we return the current value of the pointer and
    > advance the pointer to the new start of unallocated storage.  (But do
    > make allowance for alignment.)  We never free anything - once storage
    > is allocated it stays allocated.
    >
    > This scheme is simple and cheap; allocation is trivial and there are
    > no deallocation costs.  Eventually it fails when all of the available
    > storage is allocated.  Suppose, however, we have a series of
    > allocations that will/can all be released at the same time.  Then our
    > primitive allocator works very well.  As it happens, this is a very
    > common pattern. Your struct that holds pointers to arrays that must be
    > allocated in turn is a good example.
    >
    > It turns out that there can be many such sequences in the code;
    > therefore it is better to have a separate storage pool for each such
    > sequence of allocations.  The storage pool manager must have three
    > main entry points, open, get, and close.  Open creates a storage pool
    > and returns a handle to the pool.  Get gets a block of storage from a
    > given pool (specified by its handle).  Finally, close frees all of the
    > malloced storage used by the pool and marks the handle as inactive.
    >
    > The basic idea in the implementation is to use a linnked list of
    > buffers.  When the current buffer is exhausted "get" gets a new muffer
    > from malloc and adds it to the list.  Each new buffer is (a) large
    > enough to hold the request, and (b) larger than the previous buffer by
    > some factor.  (I use 1.5, but 2 is okay too.)
    >
    > As a note, the buffer free space pointer must always be an aligned
    > address.
    >
    > I have an implementation of this kind of utility on the web.  There is
    > a .c file and a .h file.  They are at:
    > <http://home.tiac.net/~cri_a/san/source_code/utl/src/stgpool.c>
    > <http://home.tiac.net/~cri_a/san/source_code/utl/include/stgpool.h>
    >
    > You probably don't want to use my implementation; it is part of a
    > package of utilities and has calls to other functions in the package.
    > However you can adapt the code to create your own stand alone version.
    > The needed modifications are pretty obvious.
    >
    > The exception is error handling.  There are three kinds of errors to
    > take into account.  One is malloc failure.  (In my version getspace
    > handles malloc failures.)  A stand alone implementation should handle
    > malloc failures.  The obvious thing to do is for "get" to call "close"
    > and then return a null pointer.  This will free all of the buffers and
    > may inactive the pool handle.
    >
    > The second kind of error is a faulty handle.  It could be a stale
    > handle or something that was never a handle.  Unfortunately the
    > reference implementation doesn't check for these kinds of errors; it
    > uses the "trust that the user gets it right" policy.
    >
    > The final kind of error is a failure of the "open" function.  This
    > could either be because of a bad argument or because of a memory
    > failure.
    >
    > I will leave the issue of error handling as an open question.
    > Finally, I'm not really happy with the handle format but that is a
    > topic for another time.


    Hi Richard,
    thank you for your long and very contructive answer. As a beginner, I
    think I will need some time to study your implementation seriously.
    However just a question, is your implementation 64bits safe and
    endianness safe?
    Cheers
     
    Voyageur Galactique, Feb 15, 2011
    #17
  18. (Richard Harter) writes:
    > On Tue, 15 Feb 2011 03:28:29 -0800 (PST), Voyageur Galactique
    > <> wrote:
    >
    >>On Feb 13, 8:29=A0am, (Richard Harter) wrote:

    > [snip]
    >
    >>Hi Richard,
    >>thank you for your long and very contructive answer. As a beginner, I
    >>think I will need some time to study your implementation seriously.
    >>However just a question, is your implementation 64bits safe and
    >>endianness safe?

    >
    > The short answer is yes. The right thing to ask about is alignment.
    > The code assumes that addresses divisible by 8 (that's 64 bits) are
    > aligned for all types. AFAIK that is true for all popular platforms.
    > If you want 128 bit alignment set NABITS to 4.


    Note that there's no portable way to determine whether a given
    address satisfies a particular alignment (unless you already know
    that it's relative to the start of a malloc()ed block). On most
    systems, you can assume that converting an address to an integer
    type gives you meaningful results -- but I've worked on systems
    where this assumption doesn't hold.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Feb 15, 2011
    #18
    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,391
    Chris Fogelklou
    Apr 20, 2004
  2. Zhiqiang Ye
    Replies:
    53
    Views:
    10,278
    Dan Pop
    Jun 28, 2004
  3. Gerard Flanagan
    Replies:
    3
    Views:
    448
    Terry Hancock
    Nov 19, 2005
  4. Christopher Benson-Manica

    Doubles and zero/negative zero

    Christopher Benson-Manica, Jun 30, 2004, in forum: C Programming
    Replies:
    4
    Views:
    680
    Walter
    Jul 1, 2004
  5. Replies:
    2
    Views:
    740
    David Harmon
    Sep 20, 2006
Loading...

Share This Page