void * vs char *

F

Francine.Neary

I've been reflecting on these two types of pointer. As far as I can
glean from books, void * and char * are functionally equivalent: the
key property of both is that they are pointers that can be faithfully
cast to any other pointer type.

The only difference seems to be that it is legal to perform arithmetic
on a char *, but not on a void *.

So if a char * really is just a more functional void *, why would
anyone ever use a void * in their code, instead of a char *?
 
P

pete

I've been reflecting on these two types of pointer. As far as I can
glean from books, void * and char * are functionally equivalent: the
key property of both is that they are pointers that can be faithfully
cast to any other pointer type.

The only difference seems to be that it is legal to perform arithmetic
on a char *, but not on a void *.

So if a char * really is just a more functional void *, why would
anyone ever use a void * in their code, instead of a char *?

The sole purpose of void*
is to reduce the amount of casts in a program.
Most pointer conversions to and from void* can be done without a cast.
Most other pointer conversions require a cast.

Before the invention of type void, char* was used instead.
 
I

Ian Collins

I've been reflecting on these two types of pointer. As far as I can
glean from books, void * and char * are functionally equivalent: the
key property of both is that they are pointers that can be faithfully
cast to any other pointer type.

The only difference seems to be that it is legal to perform arithmetic
on a char *, but not on a void *.

So if a char * really is just a more functional void *, why would
anyone ever use a void * in their code, instead of a char *?
To avoid casting every assignment of something other than a char* to and
from a char*.
 
R

Richard Tobin

So if a char * really is just a more functional void *, why would
anyone ever use a void * in their code, instead of a char *?

char * means that it points to characters or bytes. void * doesn't;
it means that it points to something of unspecified type. Even if
there was no functional difference between them, it would be
worthwhile to be able to express your intent.

-- Richard
 
K

Keith Thompson

pete said:
The sole purpose of void*
is to reduce the amount of casts in a program.
Most pointer conversions to and from void* can be done without a cast.
Most other pointer conversions require a cast.

No, that's not the *sole* purpose.

The problem with a char* is that you can't tell whether it's intended
to be a generic pointer (in pre-C89 code), or a pointer to actual
character data, or a pointer to a small integer (or an array thereof),
or a pointer to byte data (or an array thereof). The ANSI committee
invented void* to give us a generic pointer type, one that has the
advantage that you can't accidentally dereference it and obtain a
possibly meaningless char value.
Before the invention of type void, char* was used instead.

Yes.
 
F

Francine.Neary

To avoid casting every assignment of something other than a char* to and
from a char*.

I don't really follow this argument about minimizing number of casts.
For example, the following code fails - I still need to explicitly
cast p to a (struct s*) to avoid a compile-time error.

#include <stdio.h>

void call(void *);
struct s { int a; };

main()
{
struct s a;
a.a=1234;
call(&a);
return 0;
}

void call(void *p)
{
printf("%d\n",p->a);
}

 
F

Flash Gordon

I don't really follow this argument about minimizing number of casts.
For example, the following code fails - I still need to explicitly
cast p to a (struct s*) to avoid a compile-time error.

#include <stdio.h>

void call(void *);
struct s { int a; };

main()
{
struct s a;
a.a=1234;
call(&a);

No cast here that I can see, but if call took a char* as a parameter one
would be required.
return 0;
}

void call(void *p)
{
printf("%d\n",p->a);
struc s *sp = p;
printf("%d\n",sp->a);

Now it works since you are translating back to a compatible (the
original) type and not a cast in sight.

Also as a side note it would be better to be explicit about main
returning an int, especially as C99 has dropped implicit int. Best to be
specific about not taking parameters as well.
int main(void)
 
F

Flash Gordon

Flash Gordon wrote, On 19/03/07 10:10:

struc s *sp = p;

A perfect example of why I should have copied and pasted even a small
example, not retyped on a different computer. That should have been
struct not struc, of course.
 
I

Ian Collins

I don't really follow this argument about minimizing number of casts.
For example, the following code fails - I still need to explicitly
cast p to a (struct s*) to avoid a compile-time error.
No, you don't.
#include <stdio.h>
Let's start by making it legal C:
void call(void *);
struct s { int a; };

main() int main(void)
{
struct s a;
a.a=1234;
call(&a);
return 0;
}

void call(void *p)
{
printf("%d\n",p->a);
struct s *ps = p;
printf("%d\n",ps->a);
Now change call to

void call( char* );

And see what your compiler has to say. If you don't get two
incompatible type warnings, you haven't turned your warning level high
enough.
 
P

pete

I don't really follow this argument about minimizing number of casts.
For example, the following code fails - I still need to explicitly
cast p to a (struct s*) to avoid a compile-time error.

#include <stdio.h>

void call(void *);
struct s { int a; };

main()
{
struct s a;
a.a=1234;
call(&a);
return 0;
}

void call(void *p)
{
printf("%d\n",p->a);
}

The problem is that you have used the (void *) type badly.

The prototype of the call function
void call(void *p);
indicates that it is intended
to take a pointer to any type object.
But it isn't intended to take a pointer to any type object.
The printf call statement, shows that p must be a pointer
to a struct with a member "a" of type int.
The right way to write that program is:

/* BEGIN new.c */

#include <stdio.h>

struct s {
int a;
};

void call(struct s* p);

int main(void)
{
struct s a;

a.a = 1234;
call(&a);
return 0;
}

void call(struct s *p)
{
printf("%d\n", p->a);
}

/* END new.c */

mem_cpy is an example of a function that uses
void * type parameters more better.

void *mem_cpy(void *s1, const void *s2, size_t n)
{
unsigned char *p1 = s1;
const unsigned char *p2 = s2;

while (n-- != 0) {
*p1++ = *p2++;
}
return s1;
}
 
C

CBFalconer

I don't really follow this argument about minimizing number of casts.
casts. For example, the following code fails - I still need to
explicitly cast p to a (struct s*) to avoid a compile-time error.

No you don't. See modification below.
#include <stdio.h>

void call(void *);
struct s { int a; };

main()
{
struct s a;
a.a=1234;
call(&a);
return 0;
}

void call(void *p)
{
struct s *ps;

ps = p; /* alternatively use local initialization */
printf("%d\n", ps->a); /* look ma, no casts */
printf("%d\n",p->a);
}


--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
F

Francine.Neary

No, you don't.


Let's start by making it legal C:


int main(void)

???

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 :)
From 6.3.2.2:
If the expression that precedes the parenthesized argument list in a
function call consists solely of an identifier, and if no declaration
is visible for this identifier, the identifier is implicitly declared
exactly as if, in the innermost block containing the function call,
the declaration
extern int identifier();
appeared.

and from 6.5.4.3:
An empty list in a function declarator that is part of a definition of
that function specifies that the function has no parameters.

(For reference, it continues: The empty list in a function declarator
that is not part of
a definition of that function specifies that no information about the
number or types of the parameters is supplied.)
struct s *ps = p;

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.
Now change call to

void call( char* );

And see what your compiler has to say. If you don't get two
incompatible type warnings, you haven't turned your warning level high
enough.

As this conversion is lossless, I don't see why the compiler should
take it upon itself to warn me about it!
 
K

Keith Thompson

???

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 :)

If the expression that precedes the parenthesized argument list in a
function call consists solely of an identifier, and if no declaration
is visible for this identifier, the identifier is implicitly declared
exactly as if, in the innermost block containing the function call,
the declaration
extern int identifier();
appeared.
[...]

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.

[...]
As this conversion is lossless, I don't see why the compiler should
take it upon itself to warn me about it!

Because char* is not (since 1989) a generic pointer type, and a
warning is likely to tell you about a logical error in your code. In
fact, since there is no implicit conversion from struct s* to char*,
the call is a constraint violation; the compiler *must* issue a
diagnostic, and it *may* reject the program altogether.

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.
 
R

Richard Heathfield

(e-mail address removed) said:
???

main() is perfectly valid C - it defines main to be a function taking
no arguments and returning int.

Agreed. (In C99, it has to be int main() at the very least, but in C90
main() is legal.)
You may have a personal preference for
the more verbose form,

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

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.

Nevertheless, it represents a considerable gain in correctness over
printf("%d\n", p->a), wouldn't you agree?
 
F

Francine.Neary

Nevertheless, it represents a considerable gain in correctness over
printf("%d\n", p->a), wouldn't you agree?

Well, yes :)

The whole point of that example was that it was code that used a void
* but wouldn't compile unless you added in an explicit cast.
 
I

Ian Collins

[...]

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 :)
 
I

Ian Collins

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.
You said "I still need to explicitly cast p to a (struct s*) to avoid a
compile-time error", which I showed by example to be incorrect. That's
the thing with a void*, you can use implicit conversion. What harm does
a temporary pointer cause?
As this conversion is lossless, I don't see why the compiler should
take it upon itself to warn me about it!
Keith answered this better than I could.
 
R

Richard Heathfield

(e-mail address removed) said:
Well, yes :)

The whole point of that example was that it was code that used a void
* but wouldn't compile unless you added in an explicit cast.

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

Several examples of putting void * to good use can be seen in the
standard library: memcpy, memcmp, memset, qsort and bsearch all spring
to mind.
 
R

Richard Heathfield

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 :)

You must have a very small seat. :)
 
I

Ian Collins

Well, yes :)

The whole point of that example was that it was code that used a void
* but wouldn't compile unless you added in an explicit cast.
But it didn't!
*Please* don't quote signatures.
 

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,770
Messages
2,569,584
Members
45,078
Latest member
MakersCBDBlood

Latest Threads

Top