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)