[vox-tech] C - passing chars and pointer to chars

Peter Jay Salzman p at dirac.org
Sun Jun 4 07:05:22 PDT 2006


On Sat 03 Jun 06, 10:27 PM, Ken Bloom <kbloom at gmail.com> said:
> 
> Cue, the **Fundemental axiom of the C++ type system**, stated as 
> follows:
>   A* is automaitcally convertable to B* if and only if A is a B.
>   (Likewise for pass by reference).
> 
> (this is my own generalization though, and there may actually be 
> exceptions)
> 
> When handling inheritance, if Derived is a Base (Derived inherits from 
> Base), then Derived* can be automatically converted to Base*. But a 
> Derived* is not a Base*, so a Derived** cannot be automatically 
> converted to a Base**.
> 
> When dealing with templates, you cannot pass vector<Derived> where a 
> vector<Base> is expected, neither by reference nor by pointer, because 
> vector<Derived> is not a vector<Base> (because if you were to stick a 
> new Base into the vector, then it would violate the type of 
> vector<Derived>).
> 
> Supposing you wanted to create a new reference_counted_pointer<T>. A 
> reference_counted_pointer<Derived> is not a 
> reference_counted_pointer<Base>, and cannot be used as such, but you 
> would want to implement all of the appropriate conversions when writing 
> reference_counted_pointer<T> to mimic the semantics of an ordinary 
> pointer.
> 
> signed char is not an unsigned char, but they are convertable. However, 
> signed char * is not convertable to unsigned char *, and to force such 
> a conversion, you would use a reinterpret_cast<> (which reinterprets 
> the actual bits according to a different time), or as it seems from 
> Bill's post, a static_cast<> (which is generally safer when it's 
> allowed).
> 
> --Ken Bloom

Although this was interesting to read, it doesn't say much other than to
restate my observation in a more sophisticated way.

I gave good reasons *why* passing the pointers should always work.  I think
Micah really got at the heart of the matter:


   Micah said:
   Pointers to incompatible types are not guaranteed to be represented the
   same way, even though in practice they are. /All/ pointer types must be
   convertible to and from a pointer to any character type, and used as
   such, so this makes it all the more likely that they will be represented
   the same.

   Irregardless, the Standard does /require/ that a warning be given when
   you try to do this.


I think the  main point is the lack of guarantee that they're represented
the same way.  Here's what I think he means.

I *think* what Micah is saying here is that even though a char and signed
char types have the same width (1 byte) and are implemented the same way in
practise, there's no guarantee that they *are* implemented the same way.

For example, a perverse compiler writer may put a byte of dead storage (for
whatever reason) in between contiguous elements of a char array and 2 bytes
of dead storage in between contiguous elements of a signed char array.

The only guarantees are:

1. a char and signed char provide only one byte of storage.
2. ++(char *) will point to the next element of a char array.
3. ++(signed char *) will point to the next element of a signed
      char array.

and that's it.  In the scenario of the perverse compiler writer, if you made
a "char *" point to a "signed char" array, if you added one to the char
pointer, it won't quite reach the next element of the signed char array:


   signed char ar[5];
   char *c_ptr = ar;
   ++c_ptr;


memory              *        *        *        *        *        *
char array          [0]               [1]               [2]
signed char array   [0]                        [1]
                     ^                ^
                     |                |
                   c_ptr           ++c_ptr

As long as each element only provides one byte of storage, and that adding
one to the respective array worked, the standard will be satisfied.

In practise, char and signed char arrays are always implemented as:


memory              *        *        *        *        *
char array          [0]      [1]      [2]      [3]      [4]
signed char array   [0]      [1]      [2]      [3]      [4]
                     ^        ^
                     |        |
                   c_ptr   ++c_ptr



but the standard doesn't guarantee this, which is why passing different
types of char pointers works in practise, but is not absolutely guaranteed
by the standard to work.

At least, this is how I read Micah's response.  Maybe it's not correct.  :)
If this is approximately correct, then the warning makes complete sense,
even though in practise, it's not necessary.

Pete


More information about the vox-tech mailing list