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