arithmetic operations on pointer

Discussion in 'C Programming' started by variksla, Nov 25, 2013.

  1. This is, of course, true in the standards jockey sense.

    But gcc treats "void *" as being the same thing as "char *" which, for all
    practical purposes, it is.
     
    Kenny McCormack, Nov 28, 2013
    #21
    1. Advertisements

  2. variksla

    Tim Rentsch Guest

    If you mean every existing implementation, that may be true. If
    you mean every possible conforming implementation, it is not true,
    as the question may not even make sense in some environments.

    Certainly not for every conceivable conforming implementation,
    but there may be a solution in the practical sense that it works
    for all existing implementations and is likely to work on all
    reasonably plausible future implementations.
     
    Tim Rentsch, Nov 28, 2013
    #22
    1. Advertisements

  3. variksla

    Tim Rentsch Guest

    It is needed given the context in which the comment was made.
    That context was present in my posting, so you must have snipped
    it.
    I'm not assuming any such thing. My comments are about how to
    carry out a certain computation, the original expression for
    which came from a page on stackoverflow.com; they are concerned
    only with what types are needed to carry out the computation in
    a meaningful way, and did not depend on any assumptions about
    where the low bits of a pointer might end up. How the result is
    used might depend on such an assumption, but the comments above
    aren't about that.
    That assumption is dangerous, and I don't reason to take on
    take on the additional risk. The Standard makes some
    guarantees about converting pointer values to (uintptr_t);
    it makes no guarantees about converting pointer values to
    (unsigned char), which very likely is undefined behavior on
    any implementation where CHAR_BIT == 8. More practically,
    there's a good chance a compiler will complain if it sees
    a pointer value being converted to (unsigned char); for
    example, gcc issues a warning for it even without a -Wall or
    a -Wextra (or any -W's) being given.
     
    Tim Rentsch, Nov 28, 2013
    #23
  4. variksla

    Tim Rentsch Guest

    Especially since converting a pointer to a character type is
    likely to be undefined behavior, and not just some unexpected
    implementation-defined behavior.
    Note that I did say "or the moral equivalent ..." about uintptr_t.
    The original context (present in my posting but later snipped)
    tacitly assumed the existence of some type like uintptr_t; it
    seems reasonable to reference that conceptual type as "uintptr_t",
    since what is being discussed is only what makes sense given the
    context of the original (and now snipped) expression, not any
    absolute statement about whether that approach is a good idea.
     
    Tim Rentsch, Nov 29, 2013
    #24
  5. variksla

    Tim Rentsch Guest

    Here is another way to think of it. Suppose the type of p is
    'int *' and we are doing a conversion to 'char *'. Consider the
    two expressions

    ((char *) p) + 1 and (char *) (p+1)

    The expression on the left points one byte beyond where p points,
    because sizeof (char) == 1. The expression on the right points
    four bytes beyond where p points (assuming sizeof (int) == 4).
    These results hold because of how pointer arithmetic is defined -
    adding 1 to a pointer steps over exactly the number of bytes
    needed for the type that the pointer expression points to. This
    type is 'char' for the left hand expression, because of the cast,
    and 'int' for the right hand expression, because of what we said
    about p to start with.

    Now take the case when the type of p is 'void *' and we are
    converting to 'void **' :

    ((void **) p) + 1 and (void **) (p+1)

    The expression on the left points (sizeof (void *)) bytes beyond
    where p points. The expression on the right points (sizeof (void))
    bytes beyond where p points. If sizeof (void *) == sizeof (void)
    then these results would be the same. Do you think that these two
    sizes, sizeof (void *) and sizeof (void), have the same value?
    What values do you think they have?
     
    Tim Rentsch, Nov 29, 2013
    #25
  6. variksla

    Tim Rentsch Guest

    Right, but more importantly it is correct due to other practical
    considerations.
    The second half of this statement is clearly incorrect. There are
    plenty of compilers other than gcc that do not allow arithmetic on
    (void *) pointers, and groups who use these compilers often do so
    for practical reasons.
     
    Tim Rentsch, Nov 29, 2013
    #26
  7. Good point. N1570 6.3.2.3p6:

    Any pointer type may be converted to an integer type. Except as
    previously specified, the result is implementation-defined. If the
    result cannot be represented in the integer type, the behavior is
    undefined. The result need not be in the range of values of any
    integer type.

    Given CHAR_BIT == 8, it seems that there are at most 256 distinct
    pointer values that can be converted to unsigned char without
    triggering undefined behavior -- and it's likely that most of those
    256 values are not valid pointer values anyway.

    Still, it would be unsurprising for such a conversion to yield the
    low-order 8 bits of the pointer value under typical implementations.
    If uintptr_t doesn't exist (in an implementation that conforms
    to C99 or C11), it's almost certainly because no unsigned integer
    type exists that meets the requirement that conversion from void*
    and back again yields the original pointer value. In that case,
    I'm not sure what the "moral equivalent" could be. (The standard
    merely says that uintptr_t is optional, and doesn't explicitly
    state that it's ever required, but IMHO failing to provide it when
    possible would be silly.)
     
    Keith Thompson, Nov 29, 2013
    #27
  8. variksla

    Tim Rentsch Guest

    Like I was trying to say before, the original context presupposes
    an integer type capable of holding all the bits of a pointer. My
    remarks were made within that context, ie, taking as given that
    there is an integer type wide enough to hold a pointer. So the
    moral equivalent of uintptr_t is that type, whether uintptr_t
    is defined or not. My comments were meant to be taken relative
    to the earlier suggestion, and interpreted in that light, not
    as an independent statement.
     
    Tim Rentsch, Nov 29, 2013
    #28
  9. What you wrote upthread was:

    The only plausible choice for the pointer operand is uintptr_t
    (or the moral equivalent in C90, etc), which will be wide enough
    to represent the result so the right hand side cast could be
    to that type.

    The "in C90, etc" makes all the difference. In C99 and later, if
    there is an unsigned integer type wide enough to hold a pointer,
    then uintptr_t will exist (unless the implementation is perverse
    enough that it omits uintptr_t unnecessarily). I didn't realize
    until I searched upthread just now that pre-C99 implementations
    were under discussion.
     
    Keith Thompson, Dec 2, 2013
    #29
  10. variksla

    Tim Rentsch Guest

    Oh, you must have missed it. It was present in both the postings
    you responded to, and even in the quoted text (ie, not snipped)
    in the first response you gave.
     
    Tim Rentsch, Dec 3, 2013
    #30
    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.