signed/unsigned integer conversion for right shift seems against C99 rule

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



int main() {
  signed   int x = 0x80000005u;
  unsigned int y = 0x00000002u;
  signed   int z = x >> y;
  printf("0x%0x\n", z);
  return 0;
}
% gcc -std=c99 test.c 
test.c: In function 'main':
test.c:6:3: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
   printf("0x%0x\n", z);
   ^
test.c:6:3: warning: incompatible implicit declaration of built-in function 'printf'

(I'll live with that warning - just for the purpose of a clean example!)

% ./a.out
0xe0000001
  ^ SIGNED right shift

OK, so x>>y was done signed. That means both x,y were converted to
signed int (trivially).

However, that seems against C99 rules, which seem to say one should
convert to unsigned int in mixed sign equal rank situations.

First: NO INTEGER PROMOTION is done, by this rule

  any operand whose type ranks lower than int is automatically converted
  to the type int, provided int is capable of representing all values of
  the operand's original type.  If int is not sufficient, the operand is
  converted to unsigned int.

Both x and y are int, so do not rank "lower than int". Rule does not
apply. All as is. So INTEGER CONVERSION applies from there:

  If both operands are integers, integer promotion is first performed on
  both operands.  If after integer promotion the operands still have
  different types, conversion continues as follows:

They still have "different types", one being signed int and the other
being unsigned it. So CONVERSION happens:

  If one operand has an unsigned type T whose conversion rank is at
  least as high as that of the other operand's type, then the other
  operand is converted to type T.

We're there. Both are rank "int" so "at least as high" applies. One
(y) has an unsigned type T="unsigned int", so the other (x) must
be converted to T="unsigned int". Then the operation gets done as
  
 unsigned int >> unsigned int

Except it doesn't. The sign bit on the LHS was extended as the printf
showed with its "0xe..." at the front, so a shift-right-arithmetic got
done, not a shift-right-logical.

If you wonder if a SRL is available at all, it is.  Declaring both x and
y as unsigned int (i.e., change decl of x only to unsigned int) gives
the expected SRL output.

  % ./a.out
  0x20000001
    ^ zero-extended from 0x8..., not sign-extended. That's a SRL, not a SRA.

What am I reading wrong in the standards?  (which are nigh on
incomprehensible - what does "can be represented as" mean?  One can't
represent negative numbers in the unsigned version of the same type
ever, and one can't represent large positive numbers in the signed
version of the type ever, so one can never get "can be represented as").

Is this intended? Well-known to everyone but me?


% gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i586-linux-gnu/4.9/lto-wrapper
Target: i586-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10'
 --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs
 --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr
 --program-suffix=-4.9 --enable-shared --enable-linker-build-id
 --libexecdir=/usr/lib --without-included-gettext
 --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9
 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu
 --enable-libstdcxx-debug --enable-libstdcxx-time=yes
 --enable-gnu-unique-object --disable-vtable-verify --enable-plugin
 --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk
 --enable-gtk-cairo
 --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-i386/jre
 --enable-java-home
 --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-i386
 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-i386
 --with-arch-directory=i386
 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc
 --enable-targets=all --enable-multiarch --with-arch-32=i586
 --with-multilib-list=m32,m64,mx32 --enable-multilib
 --with-tune=generic --enable-checking=release --build=i586-linux-gnu
 --host=i586-linux-gnu --target=i586-linux-gnu Thread model: posix gcc
 version 4.9.2 (Debian 4.9.2-10) 

The gcc notes at https://gcc.gnu.org/c99status.html seem to say 

  integer constant type rules   GCC 3.3 
  integer promotion rules GCC 4.0 

and nothing else.  Where is current information on standards compliance?
The manual  says

  c99
           c9x
           iso9899:1999
           iso9899:199x
           ISO C99.  Note that this standard is not yet fully supported;
                                               ^^^^^^^^^^^^^^^^^^^^^^^^
           see <http://gcc.gnu.org/gcc-4.7/c99status.html> for more
           information.  The names c9x and iso9899:199x are deprecated.



Any info that would deconfuse me?

Regards to any language lawyers who pass by on the other side or this side.

PTB



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux