#define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))

Discussion in 'C Programming' started by Yevgen Muntyan, Feb 9, 2007.

  1. Consider the following macro:

    #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))

    The intent is to wrap raw memory allocation of N bytes
    into a macro which returns allocated chunk of memory
    to be used as a Type structure.
    The background: I was beaten many times (it surely
    is not my exclusive experience) by functions which
    return and accept void*. There are such functions,
    and there are cases when you can't do much about it
    (third-party libraries, containers, etc.). I make
    a conclusion: void* is evil and must be avoided when
    possible and easy. Therefore I believe it's better
    to use above macro than raw malloc. And I think this
    is a valid belief, not like believing in Santa or alive
    Elvis.

    In toy programs like posted here, when you do

    int *func (void)
    {
    int *foo = malloc (10 * sizeof *foo);
    ...
    }

    it certainly doesn't matter how you use malloc since
    it's small and easy. But in big programs, when you have
    lot of other things to worry about, it's nice to know
    that you reduced number of function calls which return
    void*. At least it's nice to know for me. Type mismatch
    here is quite a usual thing (unfortunately), since
    I deal a lot with "classes", with nested structures
    like

    struct Parent {...};
    struct Child {struct Parent parent; ...};

    It's extremely easy to mess it up, and avoiding using
    extra void* is actually a good thing. Note that this
    Child-Parent thing has nothing to do with malloc. But
    it does have a lot to do with using wrong types. And
    I don't try to think like "this is malloc, has nothing
    to do with that, void* is fine here". I just avoid using
    void*.

    Now not all people think that ALLOCIT() buys any type safety.
    Some other people do think it does.

    Anyway, it's hard to argue with more than one person
    at once, so I decided to post what I think about this
    particular "yes I want cast *here*" thing. You may
    say I want C++, you may say "Wrong.", you may prove
    using ten steps that it's wrong, whatever. I at least
    know that I am not the only person who believes in
    "cast is good in this single thing" so I am not a complete
    idiot. (Of course you can say that people who believe this
    are all idiots or wrong, but working software proves they
    aren't).

    Yevgen
     
    Yevgen Muntyan, Feb 9, 2007
    #1
    1. Advertising

  2. Yevgen Muntyan wrote:


    > The background: I was beaten many times (it surely
    > is not my exclusive experience) by functions which
    > return and accept void*. There are such functions,
    > and there are cases when you can't do much about it
    > (third-party libraries, containers, etc.). I make
    > a conclusion: void* is evil and must be avoided when
    > possible and easy.


    You need to become comfortable with void *. It's one of the most powerful
    types available in the language.
     
    Christopher Layne, Feb 9, 2007
    #2
    1. Advertising

  3. Yevgen Muntyan

    Chris Dollin Guest

    Yevgen Muntyan wrote:

    > Consider the following macro:
    >
    > #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))
    >
    > The intent is to wrap raw memory allocation of N bytes
    > into a macro which returns allocated chunk of memory
    > to be used as a Type structure.


    If it's going to be used as a pointer-to-Type, its
    fields need to be initialised. For maintainability
    the fields should be initialised close to the point
    of creation. In which case, there will be a variable
    of the right type to hand, initialised from the
    allocation expression; and so the ALLOCIT macro
    buys you hardly anything, and what little it buys,
    I think it trades off against an possible edit cycle
    when changing the type of the allocation.

    The one time I'd expect it /might/ help is when
    passing the mallocated store as an argument to
    a function, so the variable-to-hand isn't. But
    then you're passing a pointer-to-uninitialised
    store to a function, which I'd put into the
    Asking For Trouble category.

    > The background: I was beaten many times (it surely
    > is not my exclusive experience) by functions which
    > return and accept void*.


    I don't /think/ I've ever had that problem, but ...

    > There are such functions,
    > and there are cases when you can't do much about it
    > (third-party libraries, containers, etc.).


    .... I haven't worked with many of those (third-party
    thingies, I mean: of course I have container libraries).
    Were they problematic I'd wrap them and be done.

    > I make
    > a conclusion: void* is evil and must be avoided when
    > possible and easy. Therefore I believe it's better
    > to use above macro than raw malloc.


    I don't think it solves an intersting problem.

    > In toy programs like posted here, when you do
    >
    > int *func (void)
    > {
    > int *foo = malloc (10 * sizeof *foo);
    > ...
    > }
    >
    > it certainly doesn't matter how you use malloc since
    > it's small and easy. But in big programs, when you have
    > lot of other things to worry about, it's nice to know
    > that you reduced number of function calls which return
    > void*.


    Um. I don't see how the ALLOCIT macro helps /at all/
    there. Unpack?

    --
    Chris "electric hedgehog" Dollin
    "It took a very long time, much longer than the most generous estimates."
    - James White, /Sector General/
     
    Chris Dollin, Feb 9, 2007
    #3
  4. On 9 Feb, 14:52, Yevgen Muntyan <> wrote:

    > Consider the following macro:
    >
    > #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))


    well several million points for courage...


    > The intent is to wrap raw memory allocation of N bytes
    > into a macro which returns allocated chunk of memory
    > to be used as a Type structure.
    > The background: I was beaten many times (it surely
    > is not my exclusive experience) by functions which
    > return and accept void*.


    could you give some examples? I can't see how a function
    returning void* can "beat you". Assign to the wrong type?

    > There are such functions,
    > and there are cases when you can't do much about it
    > (third-party libraries, containers, etc.). I make
    > a conclusion: void* is evil and must be avoided when
    > possible and easy.


    I don't use it heavily, but I wouldn't catagorise it as "evil".
    malloc() seems ok to me.

    > Therefore I believe it's better
    > to use above macro than raw malloc. And I think this
    > is a valid belief, not like believing in Santa or alive
    > Elvis.


    well you presumably have some evidence of lowered bug
    rates or ease of use or whatever for your macro.


    > In toy programs like posted here, when you do
    >
    > int *func (void)
    > {
    > int *foo = malloc (10 * sizeof *foo);
    > ...
    >
    > }
    >
    > it certainly doesn't matter how you use malloc since
    > it's small and easy. But in big programs, when you have
    > lot of other things to worry about, it's nice to know
    > that you reduced number of function calls which return
    > void*. At least it's nice to know for me. Type mismatch
    > here is quite a usual thing (unfortunately), since
    > I deal a lot with "classes", with nested structures
    > like
    >
    > struct Parent {...};
    > struct Child {struct Parent parent; ...};
    >
    > It's extremely easy to mess it up, and avoiding using
    > extra void* is actually a good thing.


    I don't really see why. In "clc" idiom:
    Parent *p = malloc (sizeof *p);

    In your idiom
    Parent *p = ALLOCIT (Parent);

    Since your version has the type in two places I'd say an error
    was *more* likely. If my example is misleading could you
    construct a better one?

    I don't see how your macro improves type safety.


    > Note that this
    > Child-Parent thing has nothing to do with malloc.


    this confuses me. I thought this discussion was about malloc()?

    > But
    > it does have a lot to do with using wrong types. And
    > I don't try to think like "this is malloc, has nothing
    > to do with that, void* is fine here".


    I don't understand this bit.

    > I just avoid using void*.
    >
    > Now not all people think that ALLOCIT() buys any type safety.
    > Some other people do think it does.
    >
    > Anyway, it's hard to argue with more than one person
    > at once, so I decided to post what I think about this
    > particular "yes I want cast *here*" thing. You may
    > say I want C++, you may say "Wrong.", you may prove
    > using ten steps that it's wrong, whatever. I at least
    > know that I am not the only person who believes in
    > "cast is good in this single thing" so I am not a complete
    > idiot.


    I might be better to come up with a reasoned technical
    argument.


    > (Of course you can say that people who believe this
    > are all idiots or wrong, but working software proves they
    > aren't).


    well not necessarily. The cost in $/function-point may higher.
    I'm not saying it is, but simply producing "working" software
    doesn't tell you everything.


    --
    Nick Keighley

    - Note:
    - I wanted to put a check in getGuiExtract(), but it's a void
    method, inherited from the father of the father of the father of
    the
    father of the father of the father of the father of the
    father...

    So I can't modify its interface.
    (MS found in C++ comment)
     
    Nick Keighley, Feb 9, 2007
    #4
  5. Yevgen Muntyan

    Eric Sosman Guest

    Yevgen Muntyan wrote On 02/09/07 09:52,:
    > Consider the following macro:
    >
    > #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))
    >
    > The intent is to wrap raw memory allocation of N bytes
    > into a macro which returns allocated chunk of memory
    > to be used as a Type structure.
    > The background: I was beaten many times (it surely
    > is not my exclusive experience) by functions which
    > return and accept void*. There are such functions,
    > and there are cases when you can't do much about it
    > (third-party libraries, containers, etc.). I make
    > a conclusion: void* is evil and must be avoided when
    > possible and easy. Therefore I believe it's better
    > to use above macro than raw malloc. And I think this
    > is a valid belief, not like believing in Santa or alive
    > Elvis.


    Compile-time type safety is lost when you use void*,
    but there is a corresponding gain in flexibility. Keep
    in mind that C is a statically-typed language: the type
    of every expression in a program must be known at compile
    time and cannot be changed afterwards. The void* type is
    a way to evade this limitation when you need to.

    Without void* (or some other means of "turning off
    type checking"), it is hard to imagine how qsort() and
    fread() and memcpy() and the whole host of other "generic"
    functions could be written.

    > In toy programs like posted here, when you do
    >
    > int *func (void)
    > {
    > int *foo = malloc (10 * sizeof *foo);
    > ...
    > }
    >
    > it certainly doesn't matter how you use malloc since
    > it's small and easy. But in big programs, when you have
    > lot of other things to worry about, it's nice to know
    > that you reduced number of function calls which return
    > void*. At least it's nice to know for me.


    First, I disagree that the form shown above is only
    good for toy programs. I have found it useful in all
    kinds of programs, from throwaways and toys up through
    long-lived major projects.

    In "big programs" it is often desirable to invent
    more machinery for memory management than raw malloc()
    and friends provide. Such projects often have coding
    standards that discourage using malloc() directly; one
    instead calls intermediate wrappers that do additional
    work like initializing the allocated objects, keeping
    usage statistics, managing LRU caches, lumping "related"
    objects near to each other, and so on. Often, the extra
    work is highly project-specific, which is one reason that
    every big project has its own memory management framework
    (or set of frameworks).

    But ALLOCIT and similar macros are not powerful
    enough for the job! The only additional work they do
    is to pre-convert the pointer to a designated type; this
    is far short of what a "big program" usually needs. An
    alternative along the lines of

    #define ALLOCIT(type) alloc##type ()

    is perhaps defensible, but why is ALLOCIT(Thing) better
    than allocThing()?

    To answer my own semi-rhetorical question, one way
    in which it's better is that the definition might actually
    look more like

    #ifdef DEBUG
    #define ALLOCIT(type) alloc##type(__FILE__,__LINE__)
    #else
    #define ALLOCIT(type) alloc##type()
    #endif

    .... with corresponding changes in the functions themselves,
    of course. But this sort of thing can be done in other ways,
    for example by using macros to intercept the function calls:

    #idfef DEBUG
    Thing *allocThing(const char*, int);
    #define allocThing() allocThing(__FILE__,__LINE__)
    #else
    Thing *allocThing(void);
    #endif

    .... so the ALLOCIT intervention isn't an enabler or disabler
    for debugging and suchlike.

    > Type mismatch
    > here is quite a usual thing (unfortunately), since
    > I deal a lot with "classes", with nested structures
    > like
    >
    > struct Parent {...};
    > struct Child {struct Parent parent; ...};
    >
    > It's extremely easy to mess it up, and avoiding using
    > extra void* is actually a good thing. Note that this
    > Child-Parent thing has nothing to do with malloc. But
    > it does have a lot to do with using wrong types. And
    > I don't try to think like "this is malloc, has nothing
    > to do with that, void* is fine here". I just avoid using
    > void*.


    I don't understand how this example bears on the debate,
    because there are no void* or pointers of any kind at all
    in evidence. How does ALLOCIT apply to this example?

    > Now not all people think that ALLOCIT() buys any type safety.
    > Some other people do think it does.


    That it buys a small amount of type safety is, I think,
    beyond dispute. Whether it buys enough is the question.

    > Anyway, it's hard to argue with more than one person
    > at once, so I decided to post what I think about this
    > particular "yes I want cast *here*" thing. You may
    > say I want C++, you may say "Wrong.", you may prove
    > using ten steps that it's wrong, whatever. I at least
    > know that I am not the only person who believes in
    > "cast is good in this single thing" so I am not a complete
    > idiot. (Of course you can say that people who believe this
    > are all idiots or wrong, but working software proves they
    > aren't).


    As someone else remarked, you show no lack of courage.

    --
     
    Eric Sosman, Feb 9, 2007
    #5
  6. "Yevgen Muntyan" <> wrote in
    > Consider the following macro:
    >
    > #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))
    >
    > Anyway, it's hard to argue with more than one person
    > at once, so I decided to post what I think about this
    > particular "yes I want cast *here*" thing. You may
    > say I want C++, you may say "Wrong.", you may prove
    > using ten steps that it's wrong, whatever. I at least
    > know that I am not the only person who believes in
    > "cast is good in this single thing" so I am not a complete
    > idiot. (Of course you can say that people who believe this
    > are all idiots or wrong, but working software proves they
    > aren't).
    >

    C++ has a "new" operator which does what you want.

    Without getting into the merits and demerits of C++ as a language, your idea
    is obviously not so stupid that it failed to convince some very skilled
    programmers.

    However one of the most important relationships in programming is
    dependency. Your code introduces a dependency into routines which otherwise
    would be stdlib-leaf, i.e. routines that deend on the standrad library but
    nothing else. This is a big disadvantage.

    Another problem is that memory allocation is fundamental to the language. By
    introducing ALLOCIT you are forcing everyone else to adapt to your view of
    what C syntax should look like. If you were designing the language from
    scratch, then fine. However you are not, and if everyone adopted the same
    policy we would have you with ALLOCIT, another person with safealloc(),
    another with allocatememory(size_t len, int type) and so on. The upshot
    would be that programs become more difficult to understnad.
     
    Malcolm McLean, Feb 9, 2007
    #6
  7. Malcolm McLean wrote:
    > "Yevgen Muntyan" <> wrote in
    >> Consider the following macro:
    >>
    >> #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))
    >>
    >> Anyway, it's hard to argue with more than one person
    >> at once, so I decided to post what I think about this
    >> particular "yes I want cast *here*" thing. You may
    >> say I want C++, you may say "Wrong.", you may prove
    >> using ten steps that it's wrong, whatever. I at least
    >> know that I am not the only person who believes in
    >> "cast is good in this single thing" so I am not a complete
    >> idiot. (Of course you can say that people who believe this
    >> are all idiots or wrong, but working software proves they
    >> aren't).
    >>

    > C++ has a "new" operator which does what you want.
    >
    > Without getting into the merits and demerits of C++ as a language, your idea
    > is obviously not so stupid that it failed to convince some very skilled
    > programmers.
    >
    > However one of the most important relationships in programming is
    > dependency. Your code introduces a dependency into routines which otherwise
    > would be stdlib-leaf, i.e. routines that deend on the standrad library but
    > nothing else. This is a big disadvantage.
    >
    > Another problem is that memory allocation is fundamental to the language. By
    > introducing ALLOCIT you are forcing everyone else to adapt to your view of
    > what C syntax should look like. If you were designing the language from
    > scratch, then fine. However you are not, and if everyone adopted the same
    > policy we would have you with ALLOCIT, another person with safealloc(),
    > another with allocatememory(size_t len, int type) and so on. The upshot
    > would be that programs become more difficult to understnad.


    Sorry for jumping in again, but: it's not some propaganda! I am not
    saying everybody should do that or this! For instance, I am using glib
    macro in programs which use glib library, and I am happy. If I don't use
    glib, I don't use its macros and I miss them, but I never write
    them myself, it's easier to use the library.

    Now, I wanted to describe why such a macro can be good and why it *is*
    good for me. I wanted to object "it is not good for you here and now
    because it may be not good in other situation". To object "cast is
    *never* good". To object "Wrong period that's it". Oh well.
     
    Yevgen Muntyan, Feb 9, 2007
    #7
  8. Yevgen Muntyan wrote:
    > Malcolm McLean wrote:
    >> "Yevgen Muntyan" <> wrote in
    >>> Consider the following macro:
    >>>
    >>> #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))
    >>>
    >>> Anyway, it's hard to argue with more than one person
    >>> at once, so I decided to post what I think about this
    >>> particular "yes I want cast *here*" thing. You may
    >>> say I want C++, you may say "Wrong.", you may prove
    >>> using ten steps that it's wrong, whatever. I at least
    >>> know that I am not the only person who believes in
    >>> "cast is good in this single thing" so I am not a complete
    >>> idiot. (Of course you can say that people who believe this
    >>> are all idiots or wrong, but working software proves they
    >>> aren't).
    >>>

    >> C++ has a "new" operator which does what you want.
    >>
    >> Without getting into the merits and demerits of C++ as a language,
    >> your idea is obviously not so stupid that it failed to convince some
    >> very skilled programmers.
    >>
    >> However one of the most important relationships in programming is
    >> dependency. Your code introduces a dependency into routines which
    >> otherwise would be stdlib-leaf, i.e. routines that deend on the
    >> standrad library but nothing else. This is a big disadvantage.
    >>
    >> Another problem is that memory allocation is fundamental to the
    >> language. By introducing ALLOCIT you are forcing everyone else to
    >> adapt to your view of what C syntax should look like. If you were
    >> designing the language from scratch, then fine. However you are not,
    >> and if everyone adopted the same policy we would have you with
    >> ALLOCIT, another person with safealloc(), another with
    >> allocatememory(size_t len, int type) and so on. The upshot would be
    >> that programs become more difficult to understnad.

    >
    > Sorry for jumping in again, but: it's not some propaganda! I am not
    > saying everybody should do that or this! For instance, I am using glib
    > macro in programs which use glib library, and I am happy. If I don't use
    > glib, I don't use its macros and I miss them, but I never write
    > them myself, it's easier to use the library.
    >
    > Now, I wanted to describe why such a macro can be good and why it *is*
    > good for me. I wanted to object "it is not good for you here and now
    > because it may be not good in other situation". To object "cast is
    > *never* good". To object "Wrong period that's it". Oh well.


    Note the "possible and easy" part in "void* is evil and must be avoided
    when possible and easy". If I use glib, I can easily use g_new and
    I do and I'm happy. If I use POSIX-like libc, I use open() and I'm
    happy. Not always, not everywhere. I certainly need a break.
     
    Yevgen Muntyan, Feb 9, 2007
    #8
  9. Yevgen Muntyan wrote:

    > Note the "possible and easy" part in "void* is evil and must be avoided
    > when possible and easy". If I use glib, I can easily use g_new and
    > I do and I'm happy. If I use POSIX-like libc, I use open() and I'm
    > happy. Not always, not everywhere. I certainly need a break.


    Maybe you should check out perl. I hear it's got a POSIX interface.
     
    Christopher Layne, Feb 9, 2007
    #9
  10. Yevgen Muntyan

    Old Wolf Guest

    On Feb 10, 3:52 am, Yevgen Muntyan <>
    wrote:
    > Consider the following macro:
    >
    > #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))


    Have you considered:
    #define ALLOCIT(Type) ((Type*) (Type*) (Type *) \
    (&malloc)(sizeof(Type) * 1 + 0 - 0))

    ?

    > I make a conclusion: void* is evil and must be avoided
    > when possible and easy.


    I go out of my way to use (void *) as much as possible,
    when the type of the storage is not relevant.
     
    Old Wolf, Feb 12, 2007
    #10
  11. Old Wolf wrote:
    > On Feb 10, 3:52 am, Yevgen Muntyan <>
    > wrote:
    >> Consider the following macro:
    >>
    >> #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type)))

    >
    > Have you considered:
    > #define ALLOCIT(Type) ((Type*) (Type*) (Type *) \
    > (&malloc)(sizeof(Type) * 1 + 0 - 0))
    >
    > ?


    Of course. As well as

    #define ALLOCIT(Type) ((Type*)(Type*) malloc (15 * sizeof (Type) + 18))

    In fact I am using a better version:

    #define ALLOCIT(Type) ((Type*)(char*) malloc (MAX (42, sizeof (Type))))

    >> I make a conclusion: void* is evil and must be avoided
    >> when possible and easy.

    >
    > I go out of my way to use (void *) as much as possible,
    > when the type of the storage is not relevant.


    Which is irrelevant.
     
    Yevgen Muntyan, Feb 13, 2007
    #11
    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. Derek
    Replies:
    7
    Views:
    24,421
    Ron Natalie
    Oct 14, 2004
  2. Trevor

    sizeof(str) or sizeof(str) - 1 ?

    Trevor, Apr 3, 2004, in forum: C Programming
    Replies:
    9
    Views:
    664
    CBFalconer
    Apr 10, 2004
  3. Vinu
    Replies:
    13
    Views:
    1,507
    Lawrence Kirby
    May 12, 2005
  4. blufox

    sizeof( int ) != sizeof( void * )

    blufox, May 22, 2006, in forum: C Programming
    Replies:
    2
    Views:
    580
    Joe Smith
    May 22, 2006
  5. Alex Vinokur
    Replies:
    15
    Views:
    734
    Default User
    Jun 12, 2006
Loading...

Share This Page