Subject: Re: isxxx() and toupper() usage changes
To: der Mouse <mouse@Rodents.Montreal.QC.CA>
From: Ian Lance Taylor <ian@wasabisystems.com>
List: tech-userlevel
Date: 10/28/2004 14:20:25
der Mouse <mouse@Rodents.Montreal.QC.CA> writes:

> > How about actually removing the (int) cast from ctype.h?
> > I believe doing the cast is just wrong, because it only suppress
> > warnings and doesn't fix real problem.
> 
> What you really want is somethign that has the same argument-passing
> semantics as a prototyped function, it seems to me.
> 
> Unfortunately, there's no way to get that in a macro, as far as I've
> been able to tell.  (On occasion I've resorted to dummy functions
> called by macros specifically for argument type handling reasons.)
> Inline function anyone?  Is it even permitted to make is*() functions?

Yes, they can be functions.  More, according to the ISO C standard,
they are required to be functions--it is legal to declare and call,
e.g., isprint(), without including <ctype.h>.  The system may provide
macro definitions in <ctype.h> for speed, and is required to provide
function definitions for use without including <ctype.h>

I don't see how it helps, though.  If the system uses signed chars,
and you call isprint with a signed char with the value 255, then it is
going to get sign extended one way or another.  The only safe and
portable approach for the calling code is to never use plain (or
signed) char to hold the value.

When defining a macro in ctype.h, you could use gcc extensions, along
these lines:

extern unsigned char *a;
#define isprint(c) \
  (a[(__builtin_types_compatible_p(typeof(c), signed char) \
      || __builtin_types_compatible_p(typeof(c), char)) \
      ? (unsigned char)c : c]
   & __ISPRINT_FLAG)

int foo1(signed char c) { return isprint(c); }
int foo2(unsigned char c) { return isprint(c); }
int foo3(int c) { return isprint(c); }

Now foo1 and foo2 will be handled in the same way.  foo3 will of
course use the full int value, and a can be arranged to permit -1 to
succeed.

Ian