Is a void * equivalent to a char *?

P

planetzoom

Given the following code:

#include <stdio.h>

int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;

printf("%s\n", vp);

return 0;
}

Is the printf() statement correct? Or is a cast to char * required for vp?

printf("%s\n", (char *) vp);

That is, assuming a void * is pointing to a string, what is the proper way
to print the string?
 
W

Walter Roberson

planetzoom said:
Given the following code:
#include <stdio.h>
int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;
printf("%s\n", vp);
return 0;
}
Is the printf() statement correct? Or is a cast to char * required for vp?
printf("%s\n", (char *) vp);
That is, assuming a void * is pointing to a string, what is the proper way
to print the string?

void* is required to have the same representation as char*, so
in theory the above should work. (But it offends my sensibilities ;-) )
 
G

Guest

planetzoom said:
Given the following code:

#include <stdio.h>

int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;

printf("%s\n", vp);

return 0;
}

Is the printf() statement correct? Or is a cast to char * required for vp?

printf("%s\n", (char *) vp);

The cast is probably not actually required in this special case,
but...
That is, assuming a void * is pointing to a string, what is the proper way
to print the string?

....it's generally best not to rely on any two different pointer types
being passed the same way. Convert vp to char *, and you're sure not
to run into problems.
 
P

planetzoom

(e-mail address removed)-cnrc.gc.ca (Walter Roberson) wrote in

planetzoom said:
Given the following code:
#include <stdio.h>
int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;
printf("%s\n", vp);
return 0;
}
Is the printf() statement correct? Or is a cast to char * required
for vp? printf("%s\n", (char *) vp);
That is, assuming a void * is pointing to a string, what is the proper
way to print the string?

void* is required to have the same representation as char*, so
in theory the above should work. (But it offends my sensibilities ;-)
)

Ok, thank you Walter and truedfx for your explanations. :)
 
L

Lane Straatman

Walter Roberson said:
planetzoom said:
Given the following code:
#include <stdio.h>
int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;
printf("%s\n", vp);
return 0;
}
Is the printf() statement correct? Or is a cast to char * required for
vp?
printf("%s\n", (char *) vp);
That is, assuming a void * is pointing to a string, what is the proper way
to print the string?

void* is required to have the same representation as char*, so
in theory the above should work. (But it offends my sensibilities ;-) )
Correct me if I'm wrong: we're recasting a void pointer in the printf
specifier? LS
 
K

Keith Thompson

planetzoom said:
Given the following code:

#include <stdio.h>

int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;

printf("%s\n", vp);

return 0;
}

Something that nobody else has pointed out (so far) is that &array is
*not* of type char*; it's of type "char (*)[100]" (i.e., pointer to
array of 100 char). To get a pointer to the first character of the
string, use "array" (which decays to a char*) or "&array[0]".

The two expressions &array and &array[0] give you, in a sense, the
same value of two different types. Converting either to void* should
give you the same result.
Is the printf() statement correct? Or is a cast to char * required for vp?

printf("%s\n", (char *) vp);

That is, assuming a void * is pointing to a string, what is the proper way
to print the string?

It will almost certainly work without the cast, since void* and char*
are guaranteed to have the same representation. But that guarantee is
in the language to cater to old code, specifically to code written
before the void* type was introduced. And there's some question about
whether this guarantee applies to arguments to printf; it's an arcane
argument about the wording of the standard, not something you really
need to worry about.

I'd either convert the void* value to char* using a cast, or assign it
to a char* object if that happens to be more convenient.
 
P

planetzoom

planetzoom said:
Given the following code:

#include <stdio.h>

int main(void)
{
char array[100] = "What is your favorite car?";
void *vp = &array;

printf("%s\n", vp);

return 0;
}

Something that nobody else has pointed out (so far) is that &array is
*not* of type char*; it's of type "char (*)[100]" (i.e., pointer to
array of 100 char). To get a pointer to the first character of the
string, use "array" (which decays to a char*) or "&array[0]".

You know I almost made array a pointer to char, but I'm glad I didn't, as
you gave a good explanation of the difference.
The two expressions &array and &array[0] give you, in a sense, the
same value of two different types. Converting either to void* should
give you the same result.
Is the printf() statement correct? Or is a cast to char * required
for vp?

printf("%s\n", (char *) vp);

That is, assuming a void * is pointing to a string, what is the
proper way to print the string?

It will almost certainly work without the cast, since void* and char*
are guaranteed to have the same representation. But that guarantee is
in the language to cater to old code, specifically to code written
before the void* type was introduced. And there's some question about
whether this guarantee applies to arguments to printf; it's an arcane
argument about the wording of the standard, not something you really
need to worry about.

I'd either convert the void* value to char* using a cast, or assign it
to a char* object if that happens to be more convenient.

Ok, thank you Keith. 'gcc -Wall' does give a warning without the cast, but
that's probably because it has no way of knowing to what the void * points.

printf("%p\n", &array[0]);

Assuming this line were added to the above code, a cast here would also be
recommended for the same reason, even though void* and char* are guaranteed
to have the same representation?

printf("%p\n", (void *) &array[0]);
 
K

Keith Thompson

planetzoom said:
I'd either convert the void* value to char* using a cast, or assign it
to a char* object if that happens to be more convenient.

Ok, thank you Keith. 'gcc -Wall' does give a warning without the cast, but
that's probably because it has no way of knowing to what the void * points.

printf("%p\n", &array[0]);

Assuming this line were added to the above code, a cast here would also be
recommended for the same reason, even though void* and char* are guaranteed
to have the same representation?

printf("%p\n", (void *) &array[0]);

An argument could be made either way. The language pretty much
guarantees that passing a char* value for a "%p" format specifier will
work correctly.

But that guarantee exists only for historical reasons, and IMHO
depending on it is questionable style. The guarantee applies only to
pointers to char (and signed char, and unsigned char), not to pointers
to other types. The type of the array is not obvious from the printf
statement, so to verify that it's correct you'd have to hunt down the
declaration and remember the arbitrary equivalence rule. Without the
cast, the code can break if you change the type of array. If I see a
statement like that without the cast, it's hard to tell whether it was
written by a clever programmer who knows about the standard's
guarantee that char* and void* are equivalent, or by a less clever
programmer who thinks all pointers look alike.

So yes, it will work without the cast, but I'd recommend using a cast
anyway. (This is a rare case where a cast is a good idea; in most
contexts, casts should be avoided.)

You could also avoid the cast by assigning the address to a variable:

void *addr = &array[0]; /* implicit conversion from char* to void* */
printf("%p\n", addr);

But I wouldn't bother creating a variable like that just to avoid the
cast.
 
C

Christopher Layne

Keith said:
So yes, it will work without the cast, but I'd recommend using a cast
anyway. (This is a rare case where a cast is a good idea; in most
contexts, casts should be avoided.)

You could also avoid the cast by assigning the address to a variable:

void *addr = &array[0]; /* implicit conversion from char* to void* */
printf("%p\n", addr);

But I wouldn't bother creating a variable like that just to avoid the
cast.

I personally just cast it, as gcc is going to complain if you don't.
 
P

planetzoom

(This is a rare case where a cast is a good idea; in most
contexts, casts should be avoided.)

I've learned from this group that casts are often unnecesary. Thanks Keith
..
 
K

Keith Thompson

Christopher Layne said:
Keith said:
So yes, it will work without the cast, but I'd recommend using a cast
anyway. (This is a rare case where a cast is a good idea; in most
contexts, casts should be avoided.)

You could also avoid the cast by assigning the address to a variable:

void *addr = &array[0]; /* implicit conversion from char* to void* */
printf("%p\n", addr);

But I wouldn't bother creating a variable like that just to avoid the
cast.

I personally just cast it, as gcc is going to complain if you don't.

As far as I can tell, gcc doesn't complain if you pass a char* value
for a "%p" format. (It will complain if you pass a value of type
pointer to array of char.)
 
C

Christopher Layne

Keith said:
As far as I can tell, gcc doesn't complain if you pass a char* value
for a "%p" format. (It will complain if you pass a value of type
pointer to array of char.)

Actually you are correct. Strangely it didn't complain when I passed it a base
pointer of an array either. What I misremembered was this:

#include <stdio.h>

int main(void)
{
int yo = 1;

fprintf(stderr, "%p\n", &yo);

return 0;
}

gcc -g3 -W -Wall -pedantic -o g g.c
g.c: In function 'main':
g.c:7: warning: format '%p' expects type 'void *', but argument 3 has
type 'int *'

Annoying.
 
R

Richard Heathfield

Christopher Layne said:

#include <stdio.h>

int main(void)
{
int yo = 1;

fprintf(stderr, "%p\n", &yo);

return 0;
}

gcc -g3 -W -Wall -pedantic -o g g.c
g.c: In function 'main':
g.c:7: warning: format '%p' expects type 'void *', but argument 3 has
type 'int *'

Annoying.

When the compiler is good enough to tell you about a portability problem
that doesn't happen to matter on its platform but which might well
matter on others, I don't think it's annoying. I think it's a courtesy,
and a welcome one.
 
G

Guest

Keith said:
Christopher Layne said:
Keith said:
So yes, it will work without the cast, but I'd recommend using a cast
anyway. (This is a rare case where a cast is a good idea; in most
contexts, casts should be avoided.)

You could also avoid the cast by assigning the address to a variable:

void *addr = &array[0]; /* implicit conversion from char* to void* */
printf("%p\n", addr);

But I wouldn't bother creating a variable like that just to avoid the
cast.

I personally just cast it, as gcc is going to complain if you don't.

As far as I can tell, gcc doesn't complain if you pass a char* value
for a "%p" format.

You're right. Oddly enough, it does complain if you pass a pointer-to-
void for a "%s" format.
 
C

Christopher Layne

Richard said:
When the compiler is good enough to tell you about a portability problem
that doesn't happen to matter on its platform but which might well
matter on others, I don't think it's annoying. I think it's a courtesy,
and a welcome one.

Richard:

1. Solution.
2. Problem?
 
O

Old Wolf

planetzoom said:
char array[100] = "What is your favorite car?";
void *vp = &array;
printf("%s\n", vp);

Something that nobody else has pointed out (so far) is that &array is
*not* of type char*; it's of type "char (*)[100]" (i.e., pointer to
array of 100 char). To get a pointer to the first character of the
string, use "array" (which decays to a char*) or "&array[0]".

I'd either convert the void* value to char* using a cast, or assign it
to a char* object if that happens to be more convenient.

Are you sure? ISTR that a conversion of (void *) is only
guaranteed to retrieve the initial value, if it is converted
back to the type from whence it came, so in this case
the code would have to be:
printf("%s\n", *(char (*)[100])vp);

Could the DS9000 fail on:
printf("%s\n", (char *)vp);

?
 
G

Guest

Old said:
planetzoom said:
char array[100] = "What is your favorite car?";
void *vp = &array;
printf("%s\n", vp);

Something that nobody else has pointed out (so far) is that &array is
*not* of type char*; it's of type "char (*)[100]" (i.e., pointer to
array of 100 char). To get a pointer to the first character of the
string, use "array" (which decays to a char*) or "&array[0]".

I'd either convert the void* value to char* using a cast, or assign it
to a char* object if that happens to be more convenient.

Are you sure? ISTR that a conversion of (void *) is only
guaranteed to retrieve the initial value, if it is converted
back to the type from whence it came, so in this case
the code would have to be:
printf("%s\n", *(char (*)[100])vp);

Could the DS9000 fail on:
printf("%s\n", (char *)vp);

?

The standard is a bit underspecified w.r.t. pointer conversions, and
the intent is also not clear in the general case. However, for this
specific example, the standard does guarantee that any pointer to any
object can be converted to char *, and that the result points to the
first byte of the object. (void *) &array is still a pointer to an
object. So in this case, no, the DS9000 could not fail on that.
 

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,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top