Common misconceptions about C (C95)

R

Richard Tobin

gwowen said:
The free conversion of void* predates that rationale by at least 10
years

The text in question appears in a 1988 draft (the earliest I could
easily find) - are you suggesting that void * was used in 1978?

-- Richard
 
I

Ian Collins

gwowen said:
I rather suspect that's not the reason. (Although it is a nice glib
one-liner.) Rather, I suspect that the void* -> anything* conversion
exists simply because malloc() has to return something, and this
compromise does least damage to C's type system (such as it is), while
preventing the already-discussed no-prototype errors.

void* is the closest thing to a generic pointer in C. C does not have
generic programming support (such as C++ templates or Java generics), so
we have to make do with void*.
If anyone *really* trusted the programmer, there'd be no need for any
data pointer types except void*.

That would make pointer arithmetic interesting...
 
N

Nick

Ioannis Vranos said:
LOL. :)


Well, web pages are made based on some specifications, screen resolution,
etc.

No their not. Quite the reverse.

Or so they should be. Of course it's not possible to make a page that
will display on a 10x10px screen and do anything useful. But the aim
should be make them usable on the smallest screen size practical. They
most certainly should never be "based on ... screen resolution".

And yes, I know this isn't about C.
 
S

Seebs

I rather suspect that's not the reason. (Although it is a nice glib
one-liner.) Rather, I suspect that the void* -> anything* conversion
exists simply because malloc() has to return something, and this
compromise does least damage to C's type system (such as it is), while
preventing the already-discussed no-prototype errors.

That's certainly the flagship case, but it is useful in general to be able
to say "I have a pointer, I really don't know what it's a pointer to, but
it turns out that I also don't care what it's a pointer to, for some reason."

Think about, say, memcpy. There should be no cast needed for the arguments
to memcpy.
If anyone *really* trusted the programmer, there'd be no need for any
data pointer types except void*.

I don't buy the slippery slope argument.

We trust the programmer enough to provide useful tools for easily expressing
some things that programmers often want to do without a bunch of excess
typing, but we also provide tools for type-checking in cases where the
programmer wants that.

In short, if you don't like the behavior of (void *), you can always use
(unsigned char *) and cast nearly everything. If you do like that behavior
for some reason, though, it's nice to have it available.

As someone pointed out elsewhere: Part of the benefit of this is that it
means that conversions which are not obviously-safe can be flagged or
called out. The arguments passed to your qsort comparison routine can
be converted without fanfare, because that's a reasonable conversion --
you presumably know what's in the thing you called qsort on.

-s
 
S

Seebs

The free conversion of void* predates that rationale by at least 10
years so that is, at best, a post-hoc justification. Indeed, how
could "Keep the spirit of C" be a rationale in the design of C? That
rationale explains why standardization didn't change the behaviour of
void*, but it doesn't explain how that behaviour came to be.

In C, (void *) was an innovation introduced by the ANSI committee, it
did not exist in pre-ANSI C. (It came over from C++, mostly, so some
compilers had started to pick it up, but the current behavior was new.)
Incidentally, are there any misfeatures of any language that could not
be rationalized by saying "we trust the programmer"?

Tons. Imagine that we strictly prohibited type punning; that would be a
misfeature which could not be rationalized by saying "we trust the
programmer".

-s
 
R

Richard Tobin

void* is the closest thing to a generic pointer in C. C does not have
[/QUOTE]
It is a generic pointer in C.

Is there any other type of pointer it can not represent?

Pointers to functions, potentially. Presumably this is to accommodate
systems where function pointers are more complicated (and hence
bigger) than simple addresses. If necessary you can use any function
pointer type for that: it's guaranteed that you can convert back and
forth between different function types.

-- Richard
 
K

Keith Thompson

Richard said:
Heh. If I think back to C code in the past I know for a fact that if
ever a function pointer does NOT resolve to a void * then there will be
a LOT of broken systems out there should they be recompiled ...

Some implementations permit conversion between function pointers
and void* as an extension. There's nothing wrong with non-portable
code relying on such an extension. (I think POSIX guarantees it.)
But ISO C does not guarantee that such conversions retain the
original value.
 
K

Kaz Kylheku

It's straight from the Rationale that the committee wrote
to explain the reasons for some of their decisions. You'll
find it as the first -- the *first* -- bullet point in the
section headed "Keep the spirit of C" (Rationale, Section 0).

They should have rather kept the spirits in flask a little more
until after the meetings.
 
K

Kaz Kylheku

void* is the closest thing to a generic pointer in C.

It's not uniquely the closest thing. A char * is equally close. A char *
can point anywhere a void * can point, and the run-time semantics
are indistinguishable. A C program will should not require more storage, or
more execution time, because a char * was used instead of a void *.
C does not have
generic programming support (such as C++ templates or Java generics), so
we have to make do with void*.

Anything you can do with void *, you can also do with char *. (Except that you
will be required to have better manners and write some casts that you otherwise
would not have to).
 
H

Herbert Rosenau

Occasionally, yes.


Because, not casting has almost no benefit, and what you suggest is
considerably more work. Casting or not casting malloc is a piece of
coding practice, and nothing like as hard-and-fast-a-rule as it is made
out to be here. Restructuring a codebase merely to avoid it is not a
good use of my time.

Uh, you are one of the braindamaged peoples who are programming n

(int) i = (int) i + (int);

and so on?

Either you are casts all and everything regardless of usefull or not
or you casts only things tha needs to be casted only because you must
explicity give hints to the compikler to get exactly what you means.

Casting a the result of a function that returns a pointer to void is
errornous because this hinderas the compiler to tell you that you are
making errors or at least simple mistakes.

Any cast is definitely a potential error of the programmer writing
that crap!

Most of any casts are superflous - no question! However when you means
you has to use a cat in 99.99% of all cases you'll find yourself lying
to the compiler because you are unable to understund what you're
doing.



--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2R Deutsch ist da!
 
I

Ioannis Vranos

Kaz said:
It's not uniquely the closest thing. A char * is equally close. A char *
can point anywhere a void * can point, and the run-time semantics
are indistinguishable. A C program will should not require more storage,
or more execution time, because a char * was used instead of a void *.

If I am not mistaken, in C (at least C90/C95), it is only guaranteed that an
object can be considered as a sequence of unsigned chars only (and not plain
chars).


Thus we can point to any object with unsigned char *, and not char *.

Anything you can do with void *, you can also do with char *. (Except that
you will be required to have better manners and write some casts that you
otherwise would not have to).



--
Ioannis Vranos

C95 / C++03 Software Developer

http://www.cpp-software.net
 
K

Keith Thompson

Herbert Rosenau said:
Uh, you are one of the braindamaged peoples who are programming n

(int) i = (int) i + (int);

and so on?

The cast on the LHS is a contraint violation; the result of a cast
is not an lvalue. The (int) at the end is a syntax error; you have
a cast operator with no operand. If you're going to throw around
words like "braindamaged", you really should be more careful not
to make boneheaded mistakes yourself.
Either you are casts all and everything regardless of usefull or not
or you casts only things tha needs to be casted only because you must
explicity give hints to the compikler to get exactly what you means.

*Or* you don't mind using implicit conversions in some cases, but
prefer to cast explicitly in others. The C standard permits implicit
conversions to and from void* as a special case. Reasonable people
might happen to dislike this rule, and prefer to make the conversion
explicit.

I don't (I happen to think that this particular special-case rule
isn't a bad idea), but for example I dislike C99's special-case rule
that falling off the end of main() is equivalent to "return 0;",
so I write "return 0;" explicitly, even though it's not necessary.
I also put curly braces for single statements, even though, again,
it's not necessary.
Casting a the result of a function that returns a pointer to void is
errornous because this hinderas the compiler to tell you that you are
making errors or at least simple mistakes.

No, it is not erroneous, unless you're using some other meaning for
that word. I've explained this to you before.
Any cast is definitely a potential error of the programmer writing
that crap!

Most of any casts are superflous - no question! However when you means
you has to use a cat in 99.99% of all cases you'll find yourself lying
to the compiler because you are unable to understund what you're
doing.

There are reasons not to cast the result of malloc(), but they're more
subtle than you seem to realize.
 
R

Richard Tobin

Richard said:
Heh. If I think back to C code in the past I know for a fact that if
ever a function pointer does NOT resolve to a void * then there will be
a LOT of broken systems out there should they be recompiled ...

I think it was rather more plausible in the 1980s, when the standard
was written. There's been a great reduction in the range of
architectures since then.

-- Richard
 
K

Keith Thompson

I think it was rather more plausible in the 1980s, when the standard
was written. There's been a great reduction in the range of
architectures since then.

Yes, but not enough, I think, to justify changing the language
to assume that a function pointer can be stored in a void*.
For example, I think the IBM AS/400 architecture is still in use.
And I'd hesitate to predict what future architectures might look
like.

(On the other hand, the POSIX dlsym() function isn't useful if you
can't convert a void* to a function pointer; perhaps that will be
enough to prevent future architectures from breaking the assumption.)
 
R

Richard Tobin

Kaz Kylheku said:
Anything you can do with void *, you can also do with char *.

But not vice versa. You can't do arithmetic on a void *, which
is appropriate for a pointer to I-don't-know-what as opposed to
a pointer to bytes.

-- Richard
 
J

jacob navia

Richard a écrit :
Hey, Herbert. I have a good idea. Why don't you **** off? All you do is
insult and look down at people. While I realise you think you're some
big shot special programmer it seems to me you're wrong more often than
you are right. Do us all a favour and keep your advice to yourself
unless you can be civil and polite eh?

I have been one of his targets since a year or so. No insult is too
stupid, "naiva", as he calls me, is the personification of evil...
 
E

Eric Sosman

Joe said:
Richard wrote:
[ snip ]
Heh. If I think back to C code in the past I know for a fact that if
ever a function pointer does NOT resolve to a void * then there will be
a LOT of broken systems out there should they be recompiled ...
Can you cite one example? I have never seen an example of function
pointer and void pointer have any interaction.

The POSIX dynamic library API's have already been
mentioned in this thread.
 
A

Alan Curry

(On the other hand, the POSIX dlsym() function isn't useful if you
can't convert a void* to a function pointer; perhaps that will be
enough to prevent future architectures from breaking the assumption.)

It would still be useful for finding data in a shared object. And that data
could be in the form of a function pointer! So no functionality would be
lost, it would just be slightly more awkward to use.

library code:

#include <stdio.h>
static void g(void)
{
puts("hello world");
}
void (*greet)(void) = g;

main code:

#include <dlfcn.h>
int main(void)
{
void *lib = dlopen("testlib.so", RTLD_LAZY);
void (**pgreet)(void) = dlsym(lib, "greet");
(*pgreet)();
return 0;
}

No casts! This must be the superior method of using dlsym.
 
I

Ioannis Vranos

Joe said:
Richard wrote:
[ snip ]
Heh. If I think back to C code in the past I know for a fact that if
ever a function pointer does NOT resolve to a void * then there will be
a LOT of broken systems out there should they be recompiled ...
Can you cite one example? I have never seen an example of function pointer
and void pointer have any interaction.


Here is a bad style example:


/* Bad style if it compiles, under C standard. */


#include <stdio.h>


void somefunc1(void) { printf("somefunc1() was called!\n"); }

void somefunc2(void) { printf("somefunc2() was called!\n"); }




int main(void)
{
void *array[2]= { somefunc1, somefunc2 };

size_t i;


for (i= 0; i< sizeof(array)/sizeof(*array); ++i)
{
void (*p)(void)= array;

p();
}


return 0;
}


oannis@laptop:~/projects/anjuta/c/Optimized/src$ ./foobar
somefunc1() was called!
somefunc2() was called!
ioannis@laptop:~/projects/anjuta/c/Optimized/src$




--
Ioannis Vranos

C95 / C++03 Software Developer

http://www.cpp-software.net
 

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
474,008
Messages
2,570,268
Members
46,867
Latest member
Lonny Petersen

Latest Threads

Top