473,397 Members | 2,084 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

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

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
Feb 9 '07 #1
10 2558
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.
Feb 9 '07 #2
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/

Feb 9 '07 #3
On 9 Feb, 14:52, Yevgen Muntyan <muntyan.removet...@tamu.eduwrote:
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)
Feb 9 '07 #4
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.

--
Er*********@sun.com
Feb 9 '07 #5

"Yevgen Muntyan" <mu****************@tamu.eduwrote 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.

Feb 9 '07 #6
Malcolm McLean wrote:
"Yevgen Muntyan" <mu****************@tamu.eduwrote 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.
Feb 9 '07 #7
Yevgen Muntyan wrote:
Malcolm McLean wrote:
>"Yevgen Muntyan" <mu****************@tamu.eduwrote 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.
Feb 9 '07 #8
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.
Feb 9 '07 #9
On Feb 10, 3:52 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
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.

Feb 12 '07 #10
Old Wolf wrote:
On Feb 10, 3:52 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
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.
Feb 13 '07 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Tommi Mäkitalo | last post by:
Hi, what is the type of sizeof? Here is some lines of code from a programm, which I'm porting to x86-64: char buffer; unsigned size = content_size; while (size > 0 && (in.read(buffer,...
33
by: Chris Fogelklou | last post by:
What is wrong with the above? Don't worry, I already know (learned my lesson last week.) It is for the benefit of our resident compiler guru who seems to think you need the cast. I thought it...
5
by: dam_fool_2003 | last post by:
1)As i was going through the previous threads of clc I come accross that sizeof(type) could varies according to the system. limit.h macro constant(CHAR_xxx,INT_xxx,etc) will do the job of...
0
by: davidb | last post by:
Hi, does someone know how to get the length of a 2 dimensional string array: here what i need: ---------------------------------------------------------------- char **getList(void){ char...
4
by: Army1987 | last post by:
Given: #include <stdlib.h> typedef struct Node { unsigned char Data; struct Node *Next } node_t, *list_t; list_t list; Does list = list->Next = malloc(sizeof(node));
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.