Subject: Re: some unusual errors
From: [email-masked] (J. J. Farrell)

23 Sep 1998 08:34:35 -0700
Message-ID: <[email-masked]>
References: <[email-masked]>
Content-Type: text
To: [email-masked] (DJ Delorie)
Cc: [email-masked]

> From: DJ Delorie <[email-masked]>
> 
> > This looks like a bug in the macro implementation of
> > isspace(), to me; it should be casting the parameter to
> > int so it will behave in the same way as the function
> > implementation. Until a fix appears, your options are:
> 
> This discussion happens a lot in the djgpp newsgroup.  The
> result is always the same: You can't cast to int in the
> macro.  Why?  Because:

No - you're missing the point. isspace() is defined in terms
of a prototyped function which takes an int. If I were using
the function form instead of the macro form and passed a char
as the parameter, that char (or other compatible arithmetic
type) would be silently and automatically promoted to an int
before the function was invoked, exactly as if it had been
assigned to an int. There's little reason why the macro
shouldn't include an explicit cast to int which would have
almost exactly the same effect as the automatic 'cast' in
the function case.

> 1. If the programmer used the macro with a char argument
> (when char is signed), the macro can't tell the difference
> between EOF and char 0xff

While this is certainly true, I don't see what it has to do
with whether or not the macro can include a cast. Assuming
8-bit chars, 0xff in a signed char is a negative number.
Unless it's value happens to equal EOF, it breaks the
constraints on allowed values for the ctype functions, and
unleashes undefined behaviour. Whether or not it has been
promoted to an int is irrelevant.

> 2. If char is signed, a cast to int may not do what the
> macro is expecting.  The is*() macros normally expect a
> parameter in the range 0..255 or -1, but if you cast a
> signed char to int, you get values in the range -128..127 or
> -1, and your program may crash.

Again, all true but I don't see the relevance. Signed 8-bit
2's complement chars already have values in the range -128
to 127; casting to an int doesn't change these values.

> 3. Remember that getchar() returns in int - for the very
> same reason, so that EOF is not in the range of valid
> characters.  getchar() returns EOF or 0..255, which is NOT
> the same range as the range for type `signed char'.

I think we may be at cross purposes. Again this is all true
(except that there's no guarantee that EOF will be outside
the range of valid characters), but doesn't have any relevance
to whether or not a macro implementation of isspace() can or
should cast its parameter to an int.

> Basically, if you're a programmer and you've stumbled onto
> this problem, you have a problem with your code.

The cases you're talking about are bugs anyway - whether or
not the parameter gets promoted to an int is irrelevant.
Chars are just small integers; in the usual context of this
list, signed chars have values in the range -128 to 127. The
values passed to the ctype macros must be in the range 0 to
UCHAR_MAX (255 in this context) or EOF which is some specified
negative number. The programmer is required to ensure that
the parameter has a value in this range. As long as the value
is acceptable, he can put it in an int or any arithmetic type
he fancies which is smaller than int - including a signed char.
That would be correct input to the isspace() function, and
ought not to result in spurious messages from the compiler if
the macro version is used instead of the function. The best
way to make sure such messages don't appear is for the macro
to convert the parameter to an int.

Whether or not it is sensible to hold characters in signed
chars is an entirely different question. It is probably not
a good idea in general, especially if you want to use the
ctype functions on them. However, if I happen to know that
the values held in my signed chars are within the range which
is acceptable to the ctype functions, then there's no reason
why I can't pass them directly to the functions; I shouldn't
end up with confusing messages about using a char as an array
subscript!

The only problem with including a cast in the macro is that it
may suppress warnings if the macro is called with a type which
is not compatible with int. A better (but slightly more complex)
solution would be for the macro to define a working int and
assign the parameter into the int before doing anything else.
I should think the compiler ought to be able to optimise out
the inefficiencies of this.

-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".