void * vs char *

F

Francine.Neary

(e-mail address removed) said:




But it was lousy code. Sorry, but it was. That simply isn't the kind of
place where void * is a win.

Ease up there! I wasn't submitting it to a good code contest - it was
just an example to illustrate a point, proof-of-context if you like.
 
F

Francine.Neary

just an example to illustrate a point, proof-of-context if you like.

Oops meant concept of course.
 
F

Francine.Neary

You seem to be arguing that the compiler should shut up about implicit
conversions that don't lose any information; in other words, you want
C's type checking to be even weaker than it is. You're certainly
entitled to that opinion, but it's not one many people share. If you
want a generic pointer type, use void*. There are plenty of
mechanisms that let you be sloppy with types if you do it
deliberately; *I* want the compiler to warn me if I do it
accidentally.

That's an interesting way to put it. Maybe that's what's happening -
I've been forced to use Java for the last couple of years, which has
this horrible over-bearing strict typing, so maybe I'm reacting
against that now and trying to push the liberating flexibility that C
gives me...

However, I'm not completely sure it should be the job of the compiler
and not some optional lint tool to pick through my code for places
where I might just have meant something else.
 
R

Richard Heathfield

(e-mail address removed) said:
Ease up there! I wasn't submitting it to a good code contest - it was
just an example to illustrate a point, proof-of-context if you like.

Sure, but the point is that it doesn't illustrate your point well,
because it's like saying "screwdrivers are a waste of time - I tried
hammering a nail in with one and hey, I might as well have used a
hammer". Your illustration did not provide a reason not to use void *.
It just showed that there are circumstances where void * may not be
appropriate - and we already knew that.
 
S

Stephen Sprunk

main() is perfectly valid C - it defines main to be a function taking
no arguments and returning int. You may have a personal
preference for the more verbose form, but that doesn't make it
invalid. I've borrowed a copy of the ANSI Standard from the
library, so now I too can quote chapter & verse :)

That's C89/C90; C99 deprecated implicit int. There's no reason, short of
laziness, to leave off the int, and there's reason enough not to just to be
compatible with C99 if you ever end up with a compiler that supports it ;)

BTW, go grab a copy of n1124.pdf; that'll be more useful to you than a bunch
of dead trees since it's searchable, and if you lose it you just burn a few
more bits instead of having to pay the library...
A rose by any other name... I don't see that this gains anything in
terms of clarity or brevity over "printf("%d\n",((struct s*)p)->a);" -
in fact it just leads to an additional pointer floating around.

Any decent compiler will end up generating the exact same code for both
snippets. However, one is easier to understand and less likely to contain
bugs.

Remember that the primary audience for code is _not_ the compiler but rather
the coder who has to maintain the project after you. Clarity and
correctness are all that is important for 99% of code, and brevity is not
only irrelevant but also counter-productive.

(Yes, there is that 1% where performance is critical, but until you can
_prove_ there's no way to coerce your compiler to emit faster code for clear
source and there's no better algorithm available, assume you're not in that
1%.)
As this conversion is lossless, I don't see why the compiler should
take it upon itself to warn me about it!

Because it's most likely a bug, even when it's lossless.

S
 
S

Stephen Sprunk

That's an interesting way to put it. Maybe that's what's happening -
I've been forced to use Java for the last couple of years, which has
this horrible over-bearing strict typing, so maybe I'm reacting
against that now and trying to push the liberating flexibility that C
gives me...

C, unlike Java, gives you the power to shoot yourself in the foot in a
thousand different ways; however, one must consider whether the fact you
have that power means that you should do so. For instance, if you need to
cast, odds are you're doing something wrong or at least unportable. That
doesn't mean never cast, but it does mean that if the compiler is warning
you, you should generally assume it's right. Blindly adding a cast will
usually just hide a bug that will bite you later.
However, I'm not completely sure it should be the job of the compiler
and not some optional lint tool to pick through my code for places
where I might just have meant something else.

If you don't like your compiler being helpful, either turn off or ignore the
warnings. The rest of us, however, prefer to have tools tells us where our
bugs are as soon as we write them, as opposed to trying to figure out where
they are long after we've forgotten that chunk of code.

Sure, there are warnings that are just plain wrong. There's well-known
idioms that silence them in nearly all cases. For instance, most decent
compilers will complain about "if (x=y)" but not "if ((x=y)!=0)".

S
 
F

Francine.Neary

(e-mail address removed) said:



Sure, but the point is that it doesn't illustrate your point well,
because it's like saying "screwdrivers are a waste of time - I tried
hammering a nail in with one and hey, I might as well have used a
hammer". Your illustration did not provide a reason not to use void *.
It just showed that there are circumstances where void * may not be
appropriate - and we already knew that.

Maybe you're right! I guess the issue I have is that I'm not really
convinced that void * should exist at all. I mean, char * can double
up perfectly well as both a pointer to char and a "generic pointer",
but for some reason if you work with char * you need to do a lot of
extra explicit casting. At the very least, there seems to be a lot of
duplication between the function of void * and char *, whereas I
always think minimality and efficiency is a virtue.
 
F

Francine.Neary

Require an explicit cast. I used implicit conversion from void*.

Well, that's true, though the net result was you saved a pair of
parentheses in your source code, and in exchange picked up an extra
pointer to carry round!
 
I

Ian Collins

Maybe you're right! I guess the issue I have is that I'm not really
convinced that void * should exist at all. I mean, char * can double
up perfectly well as both a pointer to char and a "generic pointer",
but for some reason if you work with char * you need to do a lot of
extra explicit casting. At the very least, there seems to be a lot of
duplication between the function of void * and char *, whereas I
always think minimality and efficiency is a virtue.
No, void* serves as a generic pointer, to have char* double up (and
don't forget it used to, before void* was added to the language) adds
complexity.

void foo( char* );

Does foo() expect an generic pointer, or does foo() only expect a char*?
void* removes the ambiguity and adds clarity.

Efficiency is completely irrelevant.
 
I

Ian Collins

Well, that's true, though the net result was you saved a pair of
parentheses in your source code, and in exchange picked up an extra
pointer to carry round!
The net result was I was able to use implicit conversion from void* and
didn't have to resort to (explicit, as all casts are) casting.

I'm not sure where you get the issue with the temporary pointer from.
It's just that, a temporary variable. In the trivial example you posted
it is used exactly once, in a more complex case, it would be used
wherever the passed parameter is dereferenced.
 
A

Al Balmer

That's an interesting way to put it. Maybe that's what's happening -
I've been forced to use Java for the last couple of years, which has
this horrible over-bearing strict typing, so maybe I'm reacting
against that now and trying to push the liberating flexibility that C
gives me...

However, I'm not completely sure it should be the job of the compiler
and not some optional lint tool to pick through my code for places
where I might just have meant something else.

With most compilers, the "linting" level is controllable. Find a set
of switches you like. However, keep in mind that compilers actually
aren't always smart enough to distinguish warnings from errors.
 
F

Francine.Neary

No, void* serves as a generic pointer, to have char* double up (and
don't forget it used to, before void* was added to the language) adds
complexity.

Surely a language with a superfluous extra pointer type has "more
complexity" than one without??

It's interesting to think - if void * was added to the language, at
the time it was added people must have thought there was a compelling
reason to put it in. It would be interesting to read the discussions
of the Powers That Be from that time to see what the original
rationale was.
 
J

J. J. Farrell

Surely a language with a superfluous extra pointer type has "more
complexity" than one without??

It's interesting to think - if void * was added to the language, at
the time it was added people must have thought there was a compelling
reason to put it in. It would be interesting to read the discussions
of the Powers That Be from that time to see what the original
rationale was.

Track down a copy of the original ANSI C Standard - X3.159-1989. The
Rationale for the Committee's decisions is given in the "Rationale"
appendix. The rationale for void * is what people here have been
telling you repeatedly - to distinguish between a 'generic object
pointer' and a 'pointer to char'. To quote from the Rationale for
section 3.2.2.3

"The use of void * ("pointer to void") as a generic object pointer
type is an invention of the Committee. Adoption of this type is
stimulated by the desire to specify function prototype arguments that
either quietly convert arbitrary pointers (as in fread) or complain if
the argument type does not exactly match (as in strcmp)."

As I remember, this was one of the committee inventions which was
broadly welcomed for the clarity and reduction in confusion which it
brought to the language.
 
K

Keith Thompson

Ian Collins said:
[...]

I think you're looking at a copy of the 1990 standard. C99 dropped
implicit int.

Yes, "main()" is legal in C90 (Ian was partly mistaken on that point),
but in my opinion "int main(void)" is better.
Where I'm sitting, C == C99 :)

Ok, given that context, you're correct. (You might want to make that
a bit clearer, but we needn't re-open that debate.)

I see the smiley, but I'm ignoring it because I'm a humorless pedant.
 
K

Keith Thompson

That's an interesting way to put it. Maybe that's what's happening -
I've been forced to use Java for the last couple of years, which has
this horrible over-bearing strict typing, so maybe I'm reacting
against that now and trying to push the liberating flexibility that C
gives me...

However, I'm not completely sure it should be the job of the compiler
and not some optional lint tool to pick through my code for places
where I might just have meant something else.

There are limits to how much I'm willing to trust the compiler to
figure out what I actually meant.

In particular, if I have a function that expects a char* argument, and
I call it with a struct foo* argument, that's a constraint violation.
The compiler shouldn't try to guess that I meant to insert a cast, and
quietly do the conversion for me implicitly. Such a guess would be
wrong; it's far more likely that what I *meant* to do was write
correct code in the first place.

When I was first exposed to C (many many years ago), I was horrified
by how lax it was about certain things (I called a function with the
wrong number of arguments, and the compiler didn't complain). That
particular problem is largely solved by prototypes, but I still see C
as an extremely permissive language. Flexibility is good, but failure
to diagnose obvious errors is not.

In most other languages I've used, there's no separate "lint" tool;
the compiler does all the checking (and may have an option to control
how strict it is).

I won't go beyond that because I don't want to start a language war.
 
K

Keith Thompson

Surely a language with a superfluous extra pointer type has "more
complexity" than one without??
[...]

No, I don't think it does.

C has the concept of a generic pointer type and the concept of a
pointer-to-character type. Using the same name for both of these
concepts doesn't reduce the complexity; it merely makes the existing
complexity more difficult to deal with.

strlen() takes a char* argument. Suppose I have an abstract type that
represents a dynamic string, and it's represented as a pointer. If I
accidentally call strlen() with one of my dynamic_string pointers, I
want the compiler to tell me I've made a mistake.
 
J

Jack Klein

(e-mail address removed) said:


Agreed. (In C99, it has to be int main() at the very least, but in C90
main() is legal.)


Yes. Adding the return type makes it C99-conforming, and using the
prototype form is good style, but these are choices, not requirements.

<rant>

I have absolutely no idea why you persist in your anti-C99 crusade.

Have you tried putting the effort into lobbying the suppliers of the
compilers you use, instead of putting it into denigrating those who
point out the latest standard?

As for the use of prototype form being "good style" and not a
requirement, your attitude is questionable at best, dangerous at
worst.

A responsible professional programmer always has coding requirements,
whether they are the policy of the organization he/she works for, or
self-imposed.

It is possible even today that a professional C programmer has to
write or maintain code for a pre-standard compiler which does not
accept prototypes in declarations and definitions.

Other than that remote scenario, any C programmer who chooses to write
non-prototype function declarations and definitions, rejecting the
single most important language improvement in almost 25 years of
standardization efforts, is either ignorant or an egotistical prima
donna.

There are many reasons why so many software/firmware projects these
days are late, cancelled, seriously over budget, and/or riddled with
defects. Many of those reasons are beyond the control of the
programmer, but several of the major ones are not.

The majority of programmers (software engineers, whatever) do not
actually know the standard and specification of their programming
language, whether it is C or anything else. Of course that does not
apply to the majority of clc regulars, but we hardly represent the
average C programmer.

And the majority of programmers, regardless of language, do not know
who their real customer is. It is not the manager, the company, the
client, even the user. The real customer of computer source code is
programmers, whether it is the author at some time in the future, a
maintenance programmer who has to update the code, or participants in
code inspections.

There are very true "matters of style" in C programming. As an
example, where to put the braces is one of them, absent an
organization's coding guide. Whether to put in optional braces, is
not.

Sadly, one of the greatest impediments to better software is
programmers' egos.

</rant>
 
I

Ian Collins

Keith said:
When I was first exposed to C (many many years ago), I was horrified
by how lax it was about certain things (I called a function with the
wrong number of arguments, and the compiler didn't complain). That
particular problem is largely solved by prototypes, but I still see C
as an extremely permissive language. Flexibility is good, but failure
to diagnose obvious errors is not.
My experience was similar.

C's use of void* as a generic pointer type is an elegant solution to the
problem faced by all typed languages, writing a generic function.
My recent work has been split between four languages, C++, C, PHP and
JavaScript listed in order of "type strictness". At one extreme, a
strongly typed language requires a combination of function overloading
and generics and at the other, there isn't any type checking at all. C
fits in the middle, rudimentary type checking and a simple, elegant,
solution to the generic function: void*.
 

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,777
Messages
2,569,604
Members
45,227
Latest member
Daniella65

Latest Threads

Top