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

Micah J. Cowan micah at cowan.name
Fri Jun 2 11:57:20 PDT 2006


On Fri, Jun 02, 2006 at 11:31:43AM -0400, Peter Jay Salzman wrote:
>    char          a = 0;
>    signed char   b = 0;
>    unsigned char c = 0;
> 
>    a = b; a = c;    // fine.
>    b = a; b = c;    // fine.
>    c = a; c = b;    // fine.
> 
> You can even pass the different types of char to functions that take
> other types of char:
> 
>    void takesAChar( char x, signed char y, unsigned char z );
> 
>    takesAChar(a, b, c); takesAChar(a, c, b);  // fine.
>    takesAChar(b, a, c); takesAChar(b, c, a);  // fine.
>    takesAChar(c, b, a); takesAChar(c, a, b);  // fine.
> 
> What the compiler complains about is passing *pointers* to different
> types of char:
> 
>    void takesACharPtr( char *x, signed char *y, unsigned char *z );
> 
>    takesACharPtr(&a, &b, &c); takesACharPtr(&a, &c, &b);  // warnings.
>    takesACharPtr(&b, &a, &c); takesACharPtr(&b, &c, &a);  // warnings.
>    takesACharPtr(&c, &a, &b); takesACharPtr(&c, &b, &a);  // warnings.
> 
> The warning is:
> 
>    pointer targets in passing argument foo of bar differ in signedness.

char is a distinct type from both signed and unsigned char.  Not only
that, but it is also considered "incompatible" with the other types,
even though it is required to have precisely the same representation as
one of the other two.

The actual fact that it warns about pointers to chars of different
/signedness/ is fairly misinformative (as then, it shoud not complain
when you swap &a and &b only).

> I'm trying to understand this.  I'm fairly sure the standard says that all 3
> types of char must have the same width.  For pointer operations like:
> 
>    char s[] = "hello";
>    unsigned char *cptr = s;
>    ++cptr;
>    putc( *cptr, stdout );
> 
> will correctly print "e" because "char" and "unsigned char" have the same
> width, and when we add one to cptr, it points to the correct location in
> memory.

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.

> What I'm getting at is this.  Because all the chars have the same width, it
> doesn't matter WHAT kind of pointer you pass in to a function: char, signed
> char, or unsigned char.  Pointer arithmetic just works, and it works because
> they all have the same width.
> 
> On the other hand, the data is what gets mangled if you don't use the
> correct type:
> 
>    char c = 255;
>    printf("%d", c);
> 
> prints, as expected, -1.  Not 255.
> 
> So it seems to me that if the compiler complains about anything, it should
> complain about passing a different type of char, not a different type of
> char *.

Perhaps; but assigning between different integer types does not require
a diagnostic, even when overflow occurs (as when you assign 255 to an
8-bit signed char).

> Why does gcc 4 complain about passing different "char *" and not "char"?

Assignment between different integer types happens all the time. It's
not always well-defined (for instance, assigning 255 to an 8-bit signed
char invokes "undefined" behavior, and can cause nasal daemons to fly
out your nose, as far as the Standard is concerned).

> And is this because of the standard or is it gcc specific?

Standard. gcc3 probably didn't complain because 4 has gotten a bit more
pedantic. GCC does not issue all required diagnostics, unless you also
throw in a -pedantic flag. To get the maximum diagnostics, I usually
invoke using -W -Wall -ansi -pedantic (if it's C90).

-- 
Micah J. Cowan
Programmer, musician, typesetting enthusiast, gamer...
http://micah.cowan.name/


More information about the vox-tech mailing list