delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1998/02/11/06:34:36

Sender: vheyndri AT rug DOT ac DOT be
Message-Id: <34E18CB9.5D9E@rug.ac.be>
Date: Wed, 11 Feb 1998 12:34:17 +0100
From: Vik Heyndrickx <Vik DOT Heyndrickx AT rug DOT ac DOT be>
Mime-Version: 1.0
To: Hans-Bernhard Broeker <broeker AT physik DOT rwth-aachen DOT de>
Cc: DJ Delorie <dj AT delorie DOT com>, djgpp-workers AT delorie DOT com
Subject: Re: char != unsigned char... sometimes, sigh
References: <Pine DOT LNX DOT 3 DOT 93 DOT 980210165433 DOT 32596E-100000 AT acp3bf>

Hans-Bernhard Broeker wrote:
> 
> On Tue, 10 Feb 1998, Vik Heyndrickx wrote:
> 
> > The following is an ANSI compliant behaving macro, and it supports also
> > 'signed char'
> > It yields reasonably efficient hard-code.
> >
> > #define isupper(c) ({int t=(c);unsigned v;\
> >                      ++t;\
> >                      if(t<0)t+=256;\
> >                      v=__dj_ctype_flags[t];\
> >                      (v&__dj_ISUPPER)!=0;})
> 
> Which brings me to an idea: why should we provide is* _macros_ at all?  As
> the DJGPP libc is for gcc, anyway, why not use 'extern inline' functions
> instead? That'd save all the special casing and whatnot, and automatically
> turn it into a function call whenever gcc thinks that's the better idea...

Why would this save us the special casing?

> I.e., why not put *this* in inlines/ctype.ha:
> 
>         extern int isupper(int c);
>         extern inline int isupper(int c) {
>           return __dj_ctype_flags[c+1]&__dj_ISUPPER;
>         }

The macro's I offered were also acceptable. Every library I've seen so
far (bo*nd, djgpp, FreeBSD, gnulibc) does offer a set of macro's.
 
> > The following is an ANSI compliant behaving macro, it supports only
> > 'unsigned char'.
> > It yields the most efficient hard-code possible in many cases.
> >
> > #define isupper(c) ({int t=(c);unsigned v;\
> >                      ++t;\
> >                      v=__dj_ctype_flags[t];\
> >                      (v&__dj_ISUPPER)!=0;})
> >
> > Note that ANY change you will make to these macro's will turn them less
> > efficient. I know where I am talking about.
> 
> Could you unclose some of that knowledge? Like: why should your solution
> with two temporary variables be more efficient than a simple
> 
>         ((int)((__dj_ctype_flags[((int)(t))+1]&__dj_ISUPPER))

Because of the gnu c compiler optimization strategies. According to the
manual, you can't just assign enough to temporary variables. If you have
a look at the produced asm code, you will that this is correct. In this
particular example you could as well write "v=__dj_ctype_flags[t+1]",
but in the other (more fail safe) example I gave, this sequence is
essential. Although, I must admit that 'eggs' does a better
optimization, but that is not unexpected, is it?

> And how could a comparison ('!=0' at the end of your code) be more
> efficient than a simple cast to int? The is* functions aren't required to
> return only 1 or 0, after all, so there's no real need to translate '!=0'
> to 1.

My proposal never yields worse code, and in case the user wants to
assign the result from this macro to e.g. a char (for memory
conservation) this will always work, something that cannot be said from
your example. In case that I have two choices which offer equivalent
efficient code, I always choose the safer solution.

-- 
 \ Vik /-_-_-_-_-_-_/   
  \___/ Heyndrickx /          
   \ /-_-_-_-_-_-_/

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019