1. 程式人生 > >C語言移位知識小結

C語言移位知識小結

       關於C語言移位功能的知識小結如下:

              1,進行2的n次方計算,使用移位效率會提升很多;

              2,移位有時候會導致資料丟失,但有時候這正是我們要的功能;

              3,右移位操作是不可移植的;

              4,移位的操作符好是負數的時候,行為不確定。

       關於第4點進行一點簡單的驗證,寫程式碼如下:

#include"stdio.h"

int main(void)

{

       unsigned int a = 1;

       printf("left move 5 bit:%d\n",a << 5);

       printf("left move -5 bit:%d\n",a << -5);

       return 0;

}

       程式碼編譯執行結果:

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>gcc exp02.c

exp02.c: Infunction 'main':

exp02.c:8:2:warning: left shift count is negative

  printf("left move -5 bit: %d\n",a<< -5);

  ^

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>a

left move 5 bit:32

left move -5 bit:134217728

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>python

Python 3.6.0(v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] onwin32

Type"help", "copyright", "credits" or"license" for more information.

>>>bin(134217728)

'0b1000000000000000000000000000'

>>>len(bin(134217728)) - 2

28

>>> 

       專門加入了Python處理了一下結果,得出結論如下:

       1,移位操作符是5的時候,計算正常沒有什麼需要探討的;

       2,移位運算元是5的時候,實際的運算是左移操作了27位,這事兒很詭異的用法。很多書中會把這種操作定義為一種未定義的操作,因為不同的平臺不同編譯器會有不同的行為。如果非得找什麼規律,單純的一個驗證能夠腦補出來的也不過是27 + 5的值為32,正好是int長度。

       增加一段程式碼測試,程式碼如下;

#include"stdio.h"

int main(void)

{

       unsigned int a = 1;

       printf("left move 6 bit:%d\n",a << 6);

       printf("left move -6 bit:%d\n",a << -6);

       return 0;

}

       編譯與執行結果:

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>gcc exp02.c

exp02.c: Infunction 'main':

exp02.c:8:2:warning: left shift count is negative

  printf("left move -6 bit: %d\n",a<< -6);

  ^

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>a

left move 6 bit:64

left move -6 bit:67108864

E:\WorkSpace\02_技術實踐\01_程式語言\01_C語言\02_C和指標\exp02>python

Python 3.6.0(v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] onwin32

Type"help", "copyright", "credits" or"license" for more information.

>>>len(bin(67108864)) - 2 - 1

26

>>> 

       從上面的結果還真看出了這個結論,如此初步得出的結論是:在Windows平臺下使用gcc編譯的時候這個功能類似於迴圈右移。而我用的作業系統是Windows 10 HB,而編譯器的具體版本資訊如下:

Using built-inspecs.

COLLECT_GCC=gcc

COLLECT_LTO_WRAPPER=C:/Strawberry/c/bin/../libexec/gcc/i686-w64-mingw32/4.9.2/lto-wrapper.exe

Target:i686-w64-mingw32

Configured with:../../../src/gcc-4.9.2/configure --host=i686-w64-mingw32--build=i686-w64-mingw32 --target=i686-w64-mingw32 --prefix=/mingw32--with-gxx-include-dir=/mingw32/i686-w64-mingw32/include/c++ --enable-shared--enable-static --disable-multilib --enable-languages=c,c++,fortran,lto--enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp--enable-libatomic --enable-lto --enable-graphite --enable-checking=release--enable-fully-dynamic-string --enable-version-specific-runtime-libs--enable-sjlj-exceptions --disable-isl-version-check--disable-cloog-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug--disable-bootstrap --disable-rpath --disable-win32-registry --disable-nls--disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=i686--with-tune=generic --with-libiconv --with-system-zlib--with-gmp=/opt/build/prerequisites/i686-w64-mingw32-static--with-mpfr=/opt/build/prerequisites/i686-w64-mingw32-static--with-mpc=/opt/build/prerequisites/i686-w64-mingw32-static--with-isl=/opt/build/prerequisites/i686-w64-mingw32-static--with-cloog=/opt/build/prerequisites/i686-w64-mingw32-static--enable-cloog-backend=isl --with-pkgversion='i686-posix-sjlj, built bystrawberryperl.com project' CFLAGS='-O2 -pipe-I/opt/build/i686-492-posix-sjlj-rt_v402/mingw32/opt/include-I/opt/build/prerequisites/i686-zlib-static/include-I/opt/build/prerequisites/i686-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe-I/opt/build/i686-492-posix-sjlj-rt_v402/mingw32/opt/include-I/opt/build/prerequisites/i686-zlib-static/include-I/opt/build/prerequisites/i686-w64-mingw32-static/include' CPPFLAGS=LDFLAGS='-pipe -L/opt/build/i686-492-posix-sjlj-rt_v402/mingw32/opt/lib-L/opt/build/prerequisites/i686-zlib-static/lib -L/opt/build/prerequisites/i686-w64-mingw32-static/lib-Wl,--large-address-aware'

Thread model:posix

gcc version 4.9.2(i686-posix-sjlj, built by strawberryperl.com project)