对一个程序的思考3(移位操作之移动负数位)

在c 中左移也就是所说的逻辑移位,右端补0,

而右移是算数移位,左端补齐的是最高位的符号位。(有的编译器可能右移也是逻辑移位,但道理是一样的),这里以右移部符号位为准。

故负数左移,有可能变成正数,但负数右移,肯定还是负数。

/**********************************************************************
 * yiwei.cpp
 *Compiler: GCC,VS,VC6.0  win32
 *Author:WK
 * Last Update:  Sun 29 March 2015 10:21:44 AM CST
 ************************************************************************/
#include <stdio.h>

int main(int argc, char **argv)
{   

    int i = -9,j=9;
    printf("-9存储形式: %d %x\n", i, i);
    printf(" 9存储形式:  %d %x\n", j, j); 

	int i1 = i >> 3;int i2=i<<3;
    printf("-9右移3位:   %d %x\n", i1, i1);
	printf("-9左移3位:   %d %x\n", i2, i2);
	int j1=j >> 3;  int j2=j<<3;
    printf(" 9右移3位:    %d %x\n", j1, j1);
	printf(" 9左移3位:    %d %x\n", j2, j2);

	int i3 = i >> 33;int i4=i<<33;
    printf("-9右移33位:   %d %x\n", i3, i3);
	printf("-9左移33位:   %d %x\n", i4, i4);
	int j3=j >> 33;  int j4=j<<33;
    printf(" 9右移33位:    %d %x\n", j3, j3);
	printf(" 9左移33位:    %d %x\n", j4, j4);

	int i5 = i >> -3;int i6=i<<-3;
    printf("-9右移-3位:   %d %x\n", i5, i5);
	printf("-9左移-3位:   %d %x\n", i6, i6);
	int j5=j >> -3;  int j6=j<<-3;
    printf(" 9右移-3位:    %d %x\n", j5, j5);
	printf(" 9左移-3位:    %d %x\n", j6, j6);

	int i7 = i >> -33;int i8=i<<-33;
    printf("-9右移-33位:   %d %x\n", i7, i7);
	printf("-9左移-33位:   %d %x\n", i8, i8);
	int j7=j >> -33;  int j8=j<<-33;
    printf(" 9右移-33位:    %d %x\n", j7, j7);
	printf(" 9左移-33位:    %d %x\n", j8, j8);

    return 0;
}

运行结果是:

首先,我在这里给出的极端数字有在int 只有32位的情况下移动33位和-33,我没有给出移动3000位移动-3000位或个多,因为我认为这个移动33位和-33位已经足够代表这种情况,下来我们就分析一下结果的原因

我开始猜测编译器中右 i=n%32 程序会将大数字转化在32位平台的32位可移动范围内(我们这里的移动在int 所能表示的范围内)

于是进行了以下测试:

#include <stdio.h>

int main(int argc, char **argv)
{   

    int i = -9;
    printf("-9存储形式: %d %x\n", i, i);
	printf("\n\n");

	int i3 = i >> 33;int i4=i>>1;
    printf("-9右移33位:   %d %x\n", i3, i3);
	printf("-9右移1 位:   %d %x\n", i4, i4);
	printf("\n\n");

	int i5 = i >> -1;
	//-1的补码形式:11111111 111111111 11111111 11111111
	int i6=i>>63;//63二进制:00000000 00000000 00000000 00011111
	int i7=i>>31;
    printf("-9右移-1位:   %d %x\n", i5, i5);
	printf("-9右移63位:   %d %x\n", i6, i6);
	printf("-9右移31位:   %d %x\n", i7, i7);
	printf("\n\n");

	int i8 = i >> -33;//-33补码存储:11111111 11111111 11111111 11011111
	int i9 = i >> -1;
	int i10= i >> 63;
    printf("-9右移-33位:   %d %x\n", i9, i9);
	printf("-9左移-1 位:   %d %x\n", i9, i9);
	printf("-9左移63 位:   %d %x\n", i10, i10);

    return 0;
}

结果如下:

又进行了测试:

/**********************************************************************
 * yiwei.cpp
 *Compiler: GCC,VS,VC6.0
 *Author:WK
 ************************************************************************/
#include <stdio.h>

int main(int argc, char **argv)
{   

    int i = 9;
    printf("9存储形式: %d %x\n", i, i);
	printf("\n\n");

	int i3 = i >> 33;int i4=i>>1;
    printf("9右移33位:   %d %x\n", i3, i3);
	printf("9右移1 位:   %d %x\n", i4, i4);
	printf("\n\n");

	int i5 = i >> -1;
	//-1的补码形式:11111111 111111111 11111111 11111111
	int i6=i>>63;//63二进制:00000000 00000000 00000000 00011111
	int i7=i>>31;
    printf("9右移-1位:   %d %x\n", i5, i5);
	printf("9右移63位:   %d %x\n", i6, i6);
	printf("9右移31位:   %d %x\n", i7, i7);
	printf("\n\n");

	int i8 = i >> -33;//-33补码存储:11111111 11111111 11111111 11011111
	int i9 = i >> -1;
	int i10= i >> 63;
    printf("9右移-33位:   %d %x\n", i9, i9);
	printf("9左移-1 位:   %d %x\n", i9, i9);
	printf("9左移63 位:   %d %x\n", i10, i10);

    return 0;
}

于是我进行了如下分析:

于是我得出了一个结论: 1.当所要移动的位数(左移右边补零,右移左边补符号位)在0----32位时候就进行正常的移位,因为在int 型小于32位不会超出位数范围

2.当所要移动的位数大于32时候就进行取余32 就会转化为小于32位的数字,进行移位

3.当要移动的位数是负数的时候,就取负数补码(因为负数是在内存中以补码形式存储的)的后边5位(在32位平台上取5位,64位平台上边取6位,具体原因请参考汇编代码和计算机组成原理相关知识,我不多解释),后边5位二进制按无符号解析,如果大于32就按照步骤二进行取余32,如果小于32就进行1步骤进行移位。

(如果有以上结论有错误,欢迎大家指正!谢谢!)

时间: 2024-11-13 05:58:49

对一个程序的思考3(移位操作之移动负数位)的相关文章

对一个程序的思考(-1如何存储)

#include<iostream> using namespace std; void main() { char a[1000]; for(int i=0;i<1000;++i) { a[i] = -1 -i; } cout<<strlen(a)<<endl; } 对于上边的程序其实必须理解到内存中-1是如何存储的,而且必须明白strlen的结束符时数字零还是字符零(这个可以看我的这篇博客) 首先这个程序的结果是255不知道是否感到惊讶,下面我们分析一下 在内

对一个程序的思考6(指针与指针的指针)

#include <iostream> #include <cstring> using namespace std; char *c[] = { "ENTER", "NEW", "POINT", "FIRST" }; char **cp[] = { c+3, c+2, c+1, c }; char ***cpp = cp; int main(void) {     printf("%s&qu

对一个程序的思考4

#include<stdio.h> #include<string.h> #pragma pack(4) int main() { unsigned char puc[4]; struct tagPIM { unsigned char ucPim1; unsigned char ucData0 : 1; unsigned char ucData1 : 2; unsigned char ucData2 : 3; }*pstPimData; pstPimData = (struct t

对一个程序的思考5(C++各种函数调用)

/********************************************************************** * main.cpp * Compiler: GCC,VS,VC6.0  win32 * Author:WK * Time: 2015 3 29 ************************************************************************/ #include<iostream> using names

连载《一个程序猿的生命周期》- 40、张弛有度的工作,留给自己一些思考的时间

一个程序猿的生命周期 微信平台 口   号:职业交流,职业规划:面对现实,用心去交流.感悟. 公众号:iterlifetime 百木-ITer职业交流奋斗 群:141588103    微   博:http://www.weibo.com/u/5723400254 二维码: 希望大家能够加微信公众号,以后会分享有营养的东西. 第一家公司,小型国企,呆了7年多,为了心中仅存的理想,勇敢的跳了出来:进入第二家公司,大型股份制公司,呆了1周时间,为了发展的更快.更容易实现自己的目标,毫不犹豫的离开了:

一个程序员正在思考问题的面部表情

一个程序员正在思考问题的面部表情

像一个程序员去思考

1.模块化: 如果大家玩过上古卷轴或者像其他一些单机游戏,添加mod到游戏中是一项非常有意思的事情, 可以让游戏的趣味性大大增加.但是添加这些mod并不容易,以上古卷轴为例,你需要一个 mod管理器,这是一个基本框架,除此之外还需要各种各种的插件,这个时候很多新手就会 抱怨:为什么不把这些软件都整合到一起,这样岂不是更容易,何必整的这么复杂呢. 这里的玩家就是软件用户,他们希望越简单越好.但是作为软件的开发者最重视的是软件开发的 难易程度以及软件的可维护性.因此,程序员们强调模块化,将一个软件项

连载《一个程序猿的生命周期》-《发展篇》- 11.在麻木中寻找“源动力”

公司全体人员在南戴河召开了半年会,原董事长在大会上一再强调"求生存"(尽管取得了不错的成绩).对此,我有很强共鸣,这10多年走过来始终有一种危机感,直到现在也一刻不敢放松.强烈的求生欲望,不断的在思考发展方向,所以<一个程序猿的生命周期>第一册的命名为<生存篇>(下载). 我时常在问自己一个问题:我的源动力是什么?是否就是董事长说的"求生存"?有答案嘛?也许有吧!!! 我差不多将近一个月的时间就回山里老家一次,尽管人丁越来越少,但是仍然那么亲

连载《一个程序猿的生命周期》-《发展篇》 - 10.欠薪的高薪和稳定的相对低薪,你会选择哪个?

注:看本篇文章前,请先看<发展的路上,艰难做出抉择> 在现在的公司做工业(大)数据平台,刚开始来就我一个人,算是总体牵头人或是负责人吧.肯定是有压力,但是经过一年的努力,基础框架已经基本建好.数据链路已经打通.现在6个人的团体,总体来讲比较满意,2个80后(其中一个是89年).4个90后,已经度过了磨合期,开始走向正轨,从长远来看仍然需要扩充人员.尽管有工作压力,领导也表示放开招人,但是在招聘的过程中也是本着符合价值的基本原则,并没有一味的高薪招揽人员. 团队里只有一个人是通过社会招聘进来的,