[net.lang.c] Casting not causeing sign extention

blarson@oberon.UUCP (Bob Larson) (01/21/86)

[This is an expantion/clarifacation of a previous article I canceled a
few hours after posting.  Apologies if the cancel did not work correctly.]

In a program I am writing, I want to sign extend the eight least significant
bits of an unsigned variable to an int.  Given that char is an
8-bit and signed (not a completly portable assumption, but true on the
machine in question), assigning to a char and then to an int will cause the
sign extention I want.  Not wanting an extra temporary variable, I decided
that double casting would do what I want:  intvar=(int)(char)unsignedvar;
Upon examining the code produced, I found the later did not work correctly.
K&R (section 2.7) and two other C compilers agree with my interpritaion.

Below is a program that tests this problem.  A C compiler validation suite
should include a program that tests this use of casts.  If you would like to
add a result to my table send it to me via mail, and I will repost the table
if warented.

Machine os      compiler        #bad    of possible

Vax 750 4.2BSD  cc              0       9
Prime   Primos  cc 19.4         0       9
QT+     os9/68k microware 1.3   9       9

--Cut here--
/* Program to test sign extention by casting, by Robert A. Larson */
/* send results to ihnp4!sdcrdcf!oberon!blarson or blarson@usc-ecl.arpa */
/* note this program assumes 8-bit characters, and character tests
   are not valid otherwise */
/* note this program assumes 16-bit shorts, and short tests are not
   valid otherwise */
/* if sizeof(int) != sizeof(short) && sizeof(int) != sizeof(long)
      int to long expation testing should be added */

/* comment out as appropriate */
/* #define signedchar  /* declaration "signed char" allowed */
#define unsigchar /* declaration "unsigned char" allowed */
#define unsigshort /* declaration "unsigned short" allowed */
#define unsiglong /* declaration "unsigned long" allowed */

main(){
  int bad=0, possible=0;
  char c;
#ifdef signedchar
  signed char sc;
#endif
#ifdef unsigchar
  unsigned char uc;
#endif
  short s;
#ifdef unsigshort
  unsigned short us;
#endif
  int i;
  unsigned u;
  long l;
#ifdef unsiglong
  unsigned long ul;
#endif

  u=0x1ff;
  c=(char)u;
  if(c<0) printf("Characters are signed.\n");
  if(((char)u) != c){
    printf("((char)u) != c\n");
    bad++;
  }
  possible++;
  if(((int)(char)u) != (int)c){
    printf("((int)(char)u) != (int)c\n");
    bad++;
  }
  possible++;
  i=(int)c;
  if(((int)(char)u) != i){
    printf("((int)(char)u) != i\n");
    bad++;
  }
  possible++;
#ifdef signedchar
  sc=(signed char)u;
  if(sc>=0) printf("??? signed char are not signed.\n");
  if(((signed char)u) != sc){
    printf("((signed char)u) != sc\n");
    bad++;
  }
  possible++;
  if(((int)(signed char)u) != (int)sc){
    printf("((int)(signed char)u) != (int)sc\n");
    bad++;
  }
  possible++;
  i=(int)sc;
  if(((int)(signed char)u) != i){
    printf("((int)(signed char)u) != i\n");
    bad++;
  }
  possible++;
#endif
  if(sizeof(int)>2){
    u=0x1ffff;
    s=(short)u;
    if(((short)u) != s){
      printf("((short)u) != s\n");
      bad++;
    }
    possible++;
    if(((int)(short)u) != (int)s){
      printf("((int)(short)u) != (int)s\n");
      bad++;
    }
    possible++;
    i=(int)s;
    if(((int)(short)u) != i){
      printf("((int)(short)u) != i\n");
      bad++;
    }
    possible++;
#ifdef unsigshort
    us=(unsigned short)u;
    if(((unsigned short)u) != us){
      printf("((unsigned short)u) != us\n");
      bad++;
    }
    possible++;
    if(((int)(unsigned short)u) != (int)us){
      printf("((int)(unsigned short)u) != (int)us\n");
      bad++;
    }
    possible++;
    i=(int)us;
    if(((int)(unsigned short)u) != i){
      printf("((int)(unsigned short)u) != i\n");
      bad++;
    }
    possible++;
#endif
  }
  printf("%d bad out of a possible %d.\n",bad,possible);
}
--
Bob Larson
Arpa: Blarson@Usc-Ecl.Arpa
Uucp: ihnp4!sdcrdcf!oberon!blarson