(FAQ details:) malloc(), void * and casts

E

Eric Sosman

CJ wrote On 11/19/07 14:43,:
[... cast malloc's result or not?]

In many older implementations of the standard library, malloc is defined
to return a char * rather than a void *, so including the cast makes
your program more portable.

The original ANSI Standard was adopted in 1989. Uptake
was rapid (breathtakingly so, by comparison with that of the
1999 revision), but even so it took compiler and library
suppliers a while to grok the Standard, figure out how to
smooth the transition for existing customers, and get new
versions out -- maybe three, four years passed before ANSI-
conforming (by then, ISO-conforming) implementations were
widely available. Let's grant maximum leeway and use four
years; then the older implementations you mention had been
supplanted by 1993.

Windows NT 3.1 shipped in 1993. Question: When you
write software for Windows today, are you careful to stick
to the NT 3.1 API's to enhance portability?

Mosaic 1.0 shipped in 1993. Question: When you write
HTML today, are you careful to use only HTML 1.0 tags to
enhance cross-browser portability?

In the days when malloc() returned `char*', C did not
have prototypes; do you avoid prototypes for portability's
sake? In the days when malloc() returned `char*', there
was no <stdarg.h>; do you shun variadic functions? In the
days when malloc() returned `char*', there was no `void',
no `long double', no stringizing `#', no token-pasting `##',
no '\a' or '\v', no <limits.h>, ... Do you stay away from
all these in an attempt to cater to obsolete compilers and
libraries?

If by some peculiar twist of fate your code winds up
being compiled with Paleolithic library headers, do you
think it's better to have a cast already in place to make
sure you don't get warned of the problem than to be alerted
by a helpful diagnostic?

If you answered "Yes" to any of these questions, you
should cast the result of malloc. After fifteen years on
the island with Gilligan and the gang, a certain amount
of loony behavior is to be expected.
 
J

Julienne Walker

Without the cast, the code is erroneous and will not compiler on a
correct C++ compiler. In this case the casting is not redundant, as
it specifically create a type check which is realistically helpful in
"cut-paste" situations.

*If* you compile as C++, which I've already said can be problematic.
[...] Why add a redundant cast when it's
completely unnecessary? When someone advocates casting malloc, I'm
reminded of the following abomination:
(void)printf( "blahblahblah\n" );

The two have nothing to do with each other. No type checking is
happening here, and there is no functional purpose for it.

Likewise with casting malloc in C. There's no functional purpose for
explicitly requesting a conversion that's already implicit.
But it is an extraneous warning. You are going to get the warning for
using a function without a prototype or implementation anyways (if you
drop the inclusion of stdlib.h) -- that really what the problem is
anyways, not a pointer/int type mismatch.

The standard specifies the warning for using a function without a
prototype as an unspecified common warning. It's not guaranteed to be
produced, which is precisely why you should avoid casting away any
other help you might be getting.
What are you talking about? I write code like that, pretty much
exclusively nowadays. Its not challenging in the least. Certainly
consumers of the Better String Library appreciate it.

So you're fluent enough in both C and C++ to write code that works
with both without stepping on any toes? Good for you. But not everyone
is as expert as you are. There are far too many subtle differences in
semantics for me to recommend that anyone write "C/C++" unless they're
quite proficient in both languages.

I won't comment on your Better String Library, but a C library
designed to work with C++ does fall under the exception I was talking
about.
[...] The
counter argument has less of a foundation than you claim the original
argument to have.

The original justification is blatantly false. My justification
corresponds to real issues, and real code.

The original justification may be false, but only when you apply your
own restrictions to it. While it's nice that you can successfully
torpedo a rationale that you've butchered into weakness, the same
arguments don't apply fully to the complete rationale.
 
C

CJ

That's a very rare corner case. Such libraries probably require
malloc.h as well.

I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

Writing in the common subset of K&R C, C89 and C99 where possible costs
you very little, and buys you additional portability.
 
I

Ian Collins

CJ said:
I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

Writing in the common subset of K&R C, C89 and C99 where possible costs
you very little, and buys you additional portability.
Common subset of K&R C and C99?
 
F

Flash Gordon

CJ wrote, On 19/11/07 22:59:
I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

There is not much when compared to about of post 1995 kit. Personally
I've never needed pre-ANSI compatibility.
Writing in the common subset of K&R C, C89 and C99 where possible costs
you very little, and buys you additional portability.

Well, when I stripped out the handling of pre-ANSI C from a code-base I
needed to work on it made it far easier to read. So the K&R
compatibility was costing a significant amount.
 
K

Keith Thompson

CJ said:
I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

Writing in the common subset of K&R C, C89 and C99 where possible costs
you very little, and buys you additional portability.

It costs you the ability to use prototypes (or at least the ability to
use prototypes without lots of #ifdefs). It also costs you the ability
to assume specific declarations for standard library functions. Let's
see, does malloc() return a void* or a char*? Does it expect a size_t,
or an int, or an unsigned long?

The available dialects of C are basically C99, C90, and N different
pre-ANSI dialects. Catering to pre-ANSI implementations causes the
complexity of writing compatible code to explode.

There may still be some ancient implementations still in use, and if you
really need to worry about that, you have my sympathy. But
<ASSUMPTION>most</ASSUMPTION> C programmers just don't need to worry
about that anymore.
 
C

CBFalconer

Julienne said:
.... snip ...

If you want C++, use C++. Trying to write C++ compatible C, while
disturbingly common, is also surprisingly difficult to get right.
The counter argument has less of a foundation than you claim the
original argument to have.

Yes, it is useful to write C++ compatible C. But only occasionally.
I see this as an exception to the rule and not a reason to ignore
the rule.

I consider it totally purposeless. If needed to link C code with
C++ code, that ability is already present in C++. If proposed for
'portability' there are many systems with C compilers that don't
have C++ compilers, but the reverse is not true, or at least very
rare. At the same time any such attempts run into the raw fact
that C++ is not a true superset of C; there are various basic
incompatibilities, which can lead to embarassing failures.
 
D

dj3vande

*If* you compile as C++, which I've already said can be problematic.

But problematic enough to be worth the extra checking you get by
compiling it as a different language? Actually, why stop at only one
extra language? I bet if everybody made sure that their code was
acceptable as C, C++, Pascal, Java, Fortran, *and* Haskell, that would
make sure that *ABSOLUTELY NO* incorrect code survived!


dave
 
E

Eric Sosman

Paul said:
[... on casting the result of malloc() ...]
Without the cast, the code is erroneous and will not compiler on a
correct C++ compiler. [...]

With or without the cast, the code is erroneous and
will not compile with a correct Scheme compiler, Fortran
compiler, PL/1 compiler, Pascal compiler, SNOBOL compiler,
COBOL compiler, or BAL assembler. What's your C problem?

Years ago I saw code that implemented the famous "Hello,
World!" program in C, Fortran, and csh (? some Unix shell,
at any rate) simultaneously. That is, the exact same source
code printed "Hello, World!" when compiled as C, or compiled
as Fortran, or interpreted by csh(?). It was an amusing and
ingenious construct, but not a useful guide to good style in
any one of those three languages.
 
K

Keith Thompson

But problematic enough to be worth the extra checking you get by
compiling it as a different language? Actually, why stop at only one
extra language? I bet if everybody made sure that their code was
acceptable as C, C++, Pascal, Java, Fortran, *and* Haskell, that would
make sure that *ABSOLUTELY NO* incorrect code survived!

The difference, of course, is that writing code that compiles
simultaneously as C and Pascal, or as C and Haskell, would be completely
batcrackers insane (unless you're going for deliberate obfuscation).
Writing code that's simultaneously valid in C and C++, on the other
hand, is possible, and there are occasional valid reasons for doing so.
Two examples: P.J. Plauger writes libraries that are valid C and C++
(and is more than competent enough to do so), and if I recall correctly
Kernighan and Ritchie used a C++ compiler to test the code samples in
K&R2 (because C compilers didn't yet support prototypes). The former is
rare, and the latter is no longer much of an issue now that C90 is
widely available.

My personal opinion, in contrast to Paul Hsieh's, is that writing code
that's valid C and C++ is very rarely (not never) a good idea. They're
two different languages, and even though much valid well-written C code
can be valid C++ code, it's rarely valid *well-written* C++ code. Paul
argues that C++ compilers do better checking, but I think that a
properly configured lint tool will do the same checking.
 
S

santosh

CJ <[email protected]> said:
I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

Writing in the common subset of K&R C, C89 and C99 where possible
costs you very little, and buys you additional portability.

While I can understand the problem of maintaining old code, I'd be very
surprised of any current systems which have only a pre-ANSI C compiler
available. Can you give an example?
 
O

Old Wolf

In many older implementations of the standard library, malloc is defined
to return a char * rather than a void *, so including the cast makes
your program more portable.

I wouldn't include other languages (or other versions
of the same language) in my definition of 'portable'.

A portable C89 program means it can be compiled by C89
compilers on any other system that has one.

Would you call it 'enhancing portability' to write your
program in the common subset of C and Perl? Such
programs certainly do exist.
 
O

Old Wolf

I won't comment on your Better String Library, but a C library
designed to work with C++ does fall under the exception I was talking
about.

He doesn't write a C library to work with C++. (FWIW, almost every
C library works with C++, with minor header tweaks). He writes code
that can either be compiled as a C library, or as a C++ library.
Nobody can really explain why he does this.
 
J

Joachim Schmitz

santosh said:
While I can understand the problem of maintaining old code, I'd be very
surprised of any current systems which have only a pre-ANSI C compiler
available. Can you give an example?
Not 100% sure, but I believe with HP/UX you get a pre ANSI Compiler as long
as you don't buy/license a 'real' one (that ancient compiler seems to be
needed/sufficient to create a new kernel)

Bye, Jojo
 
S

santosh

Joachim Schmitz said:
Not 100% sure, but I believe with HP/UX you get a pre ANSI Compiler as
long as you don't buy/license a 'real' one (that ancient compiler
seems to be needed/sufficient to create a new kernel)

Understood, but I was asking for an example of a platform where a
pre-ANSI compiler is the _only_ option.

Certain embedded systems might have non-conformant compilers, but that's
(I think) different from a pre-ANSI compiler.
 
R

Richard Bos

CJ said:
I'm not sure I'd call it "very rare" - there's plenty of old iron out
there.

Writing in the common subset of K&R C, C89 and C99 where possible costs
you very little, and buys you additional portability.

I'm sorry: writing

func()
short a;
float b;
{
...
}

instead of

int func(short a, float b)
{
...
}

costs very little? You might want to rethink that.

In the case under discussion, casting malloc() calls causes your brain
to rot. To be precise, it causes deterioration, frequently irreversible,
of the parts that let you think "Hey! A cast! Better be careful, there's
something iffy going on here."

Richard
 
F

Flash Gordon

santosh wrote, On 20/11/07 14:26:
Understood, but I was asking for an example of a platform where a
pre-ANSI compiler is the _only_ option.

You can also get gcc for HP/UX, so you do not even have to pay to have a
C89/C90/C95 compiler.

I believe there are still a few people using a few ancient machines (or
emulations of them) where the machine itself pre-dates the ANSI standard
by far enough that no one has written an compiler for the target that
supports the standard. I seem to remember someone on comp.std.c
mentioning that they were in this position. I can't remember why they
were using such ancient systems.
Certain embedded systems might have non-conformant compilers, but that's
(I think) different from a pre-ANSI compiler.

It is very different.
 
L

Lorenzo Villari

Urg. I shouldn't have put myself out there, now I can't dig up a
concrete example. I am an avid user of the WATCOM C/C++ compilers.
They decided to supply their C and C++ solutions as two separate
compilers and at various times they have clearly put more effort into
their C++ optimizer. I had some benchmarks somewhere long ago that
demonstrated this.


Well C compilers certainly still exist, and some vendors, like
Microsoft, continue to use a single compiler that compiles both
languages. But GNU, and Watcom have clearly taken the two compiler
approach (but in different ways; GNU uses a common back end, at least
for now.)

There's a section in your site in which you do compare the assembler
generated by the watcom compiler, in contrast with one done by hand by you.
Over the first assembler listing I can read:

"WATCOM C/C++ v10.0a output"

so one has the impression they give identical output... but why have you
used the C one anyway ? :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top