Skip to Content.
Sympa Menu

freetds - RE: [freetds] casts and warnings

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: christos AT zoulas.com (Christos Zoulas)
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>, <ml AT freetds.org>
  • Cc:
  • Subject: RE: [freetds] casts and warnings
  • Date: Thu, 10 Mar 2005 11:57:37 -0500

On Mar 10, 11:30am, LowdenJK AT bernstein.com ("Lowden, James K") wrote:
-- Subject: RE: [freetds] casts and warnings

| Christos,
|
| In an earlier message, you made the irrefutable point (and, for me,
| that's saying something) that because some charsets include 8-bit
| characters, treating a character as a signed entity is a source of
| trouble whenever it's promoted to int. I spent a few hours researching
| that last night. It's not easy to find definitive sources of model
| code. "The Annotated Annotated C Standard"
| (http://www.lysator.liu.se/c/schildt.html) points out that even the
| Standard itself includes error-prone illustrations, cf. 7.9.10.2 and
| 7.9.10.3.

Well, 7.9.10.2 is a bit confusing. Notice that it does not declare 'ch'.
Guess what? The only valid declaration of 'ch' is 'int' because on a machine
where chars are unsigned by default, the test:

while ((ch = fgetc(fp)) != EOF) {
...
}

will never terminate. 7.9.10.3 comes to the same conclusion. Of course
all the "character getting" functions in stdio.h return integers and
all the "character putting" functions have integer arguments already
so that is not an issue.

[...]

| The right approach -- fighting words, to be sure -- is to declare the
| data accurately. fgets(3) really does return an array of 8-bit
| entities; its char* argument is an ASCII anachronism (although "plain
| char" may be signed or not). In no sense do the elements of query_line
| ever represent negative values.
|
| Once we know we're dealing with an unsigned character, we can allow it
| to be promoted to int willy-nilly. Granted, we have to be careful of
| contructions like (*p - '0') that might wrap around, but that's just a
| variation of the usual bounds checking.
|
| I think declaring the data unsigned will lead to fewer casts and (by
| definition) cleaner code, don't you?

I've tried it and it ends up being a worse mess. You start needing
casts everywhere you do string operations, since most of the
traditional (pre-internationalization) C library API's use 'char'
instead of 'unsigned char'. This makes the code harder to read and
is much more intrusive than adding casts the isfoo() macros or
replace them with ISFOO() macros that do the casting for you. To
top this off, some tools that keep track of the data types inside
variables and allocated memory will bitch at you if you tried to
store/fetch signed chars from unsigned chars and vice versa, so
you'd have to either ignore those warnings, or annotate the code
for them. And then there is the issue of overflow, as you mentioned.

If you always assume gcc you can just compile with -funsigned-char
and the problem goes away... just kidding.

| More important, most compilers will complain about passing unsigned
| char* to a function takikng char*, whereas many will not (and should
| not) complain about passing a char to an int when there is an implicit
| unsigned constraint. IOW, I'm sure there are other cases of calling
| isspace & Co. with a plain char. Declaring the input unsigned (where
| appropriate) fixes all of them and all future ones, at the cost of
| requiring casts for char*.

Yes, unfortunately you have to pay attention when you pass a char
into an integer argument. And you are right, having an unsigned char
fixes the problem but at the cost of *many* casts.

| Of course, of course, we're only postponing the real problem. None of
| this works with UTF-8.

Yes, another way to fix all this is to start looking at wchar.h and
wctype.h.

christos




Archive powered by MHonArc 2.6.24.

Top of Page