Is a void * equivalent to a char *?

Discussion in 'C Programming' started by planetzoom, Feb 7, 2007.

  1. planetzoom

    planetzoom Guest

    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?
     
    planetzoom, Feb 7, 2007
    #1
    1. Advertisements

  2. void* is required to have the same representation as char*, so
    in theory the above should work. (But it offends my sensibilities ;-) )
     
    Walter Roberson, Feb 7, 2007
    #2
    1. Advertisements

  3. planetzoom

    Guest Guest

    The cast is probably not actually required in this special case,
    but...
    ....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.
     
    Guest, Feb 7, 2007
    #3
  4. planetzoom

    planetzoom Guest

    -cnrc.gc.ca (Walter Roberson) wrote in

    Ok, thank you Walter and truedfx for your explanations. :)
     
    planetzoom, Feb 7, 2007
    #4
  5. Correct me if I'm wrong: we're recasting a void pointer in the printf
    specifier? LS
     
    Lane Straatman, Feb 7, 2007
    #5
  6. 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.
    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.
     
    Keith Thompson, Feb 7, 2007
    #6
  7. planetzoom

    planetzoom Guest

    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.
    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]);
     
    planetzoom, Feb 8, 2007
    #7
  8. 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.
     
    Keith Thompson, Feb 8, 2007
    #8
  9. I personally just cast it, as gcc is going to complain if you don't.
     
    Christopher Layne, Feb 8, 2007
    #9
  10. planetzoom

    planetzoom Guest

    I've learned from this group that casts are often unnecesary. Thanks Keith
    ..
     
    planetzoom, Feb 8, 2007
    #10
  11. 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.)
     
    Keith Thompson, Feb 8, 2007
    #11
  12. 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.
     
    Christopher Layne, Feb 8, 2007
    #12
  13. Christopher Layne 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 Heathfield, Feb 8, 2007
    #13
  14. planetzoom

    Guest Guest

    You're right. Oddly enough, it does complain if you pass a pointer-to-
    void for a "%s" format.
     
    Guest, Feb 8, 2007
    #14
  15. planetzoom

    CBFalconer Guest

    CBFalconer, Feb 8, 2007
    #15
  16. planetzoom

    Guest Guest

    Casts can hide other errors, but they themselves are more often bad
    style than actual errors.
     
    Guest, Feb 8, 2007
    #16
  17. Richard:

    1. Solution.
    2. Problem?
     
    Christopher Layne, Feb 8, 2007
    #17
  18. planetzoom

    Old Wolf Guest

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

    ?
     
    Old Wolf, Feb 8, 2007
    #18
  19. planetzoom

    Guest Guest

    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.
     
    Guest, Feb 10, 2007
    #19
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.