C语言 位运算问题。

#include<stdio.h>
main()
{short int n;
scanf("%o",&n);
short int change(short int,int,int);
int n1,n2;
scanf("%d %d",&n1,&n2);
n=change(n,n1,n2);
printf("%d %o\n",n,n);}

short int change(short int n,int n1,int n2)
{n=n<<(n1-1);
n=n>>((n1-1)+(16-n2));
return(n);}
这个程序是想把一个八进数的n1到n2位的数保存下来,例如输入n=173253,n1=5,n2=8,173253大概表示:****0110********,第5到8位是0110,运行结果就可以得到6 6。
但我输入n=123,n1=12,n2=15,八进制123是0000000001010011,我想保存12到15位,即1001,我觉得应该输出9 11才对,为什么运行结果是-7 37777777771。
就是说我这个程序在输入173253时能得到正确答案,输入123就不行,没有通用性?还是程序本身就是错的?求高手指点。

改为无符号即可,楼主自行看图。ejiizhg 给的答案是对的,右移带符号则会补1,无符号右移则补0

追问

厉害了,你这么一改真就可以了,奇怪,昨天好像也试过,怎么没成功。
那请问没改之前的程序,即有符号n,在获得123数据左移又右移之后变成1111 1111 1111 1001对吧,这个数就是十进制的-7,这我明白,但他为什么用八进制打印是37777777771,我觉的应该是177771才对吧,难道它变成了32位的?我定义的是short int 啊,不是两字节16位吗?

厉害了,你这么一改真就可以了,奇怪,昨天好像也试过,怎么没成功。
那请问没改之前的程序,即有符号n,在获得123数据左移又右移之后变成1111 1111 1111 1001对吧,这个数就是十进制的-7,这我明白,但他为什么用八进制打印是37777777771,我觉的应该是177771才对吧,难道它变成了32位的?我定义的是short int 啊,不是两字节16位吗?

追答

编译器会有一个默认的设置
位移操作在未明确指定类型的时候会先转换成int然后再位移。
而且也因为你的返回值写的是int。如果直接写 printf("%o", n<<4);输出的通常也是32位的。

温馨提示:内容为网友见解,仅供参考
第1个回答  2014-01-20
你略搞笑了吧……你的“八进制123是0000000001010011”,难道就不可以是“1010011”吗,这样根本就没有第12位和15位了。

正解是第1位是个位,所以你要的1001其实是第2位到第5位。前导0可以有很多个,所以你要的第12位到第15位应该是0。

至于你的程序有没有问题,先把我说的这个改正再看看呢。追问

大哥,我初学啊,你的意思是n1,n2输入2,5吗,不是3,6吗,不过好像都不行啊,能帮我看下程序不?

追答

初学啊,不好意思啦。


一个数在计算机中是总是二进制表示的,位运算也是对这个二进制数操作。所以比如一个int类型(一般是4个字节,就是32位)的123在计算机中就是00000000 00000000 00000000 01111011。注意,最右边的1是第0位(按计算机的方式来数数),最左边是第31位。把它变成八进制,就是从最低位(也就是第0位)开始,连续三位变成一个数,就是 001 111 011 -> 173 。


你要保存的第几位到第几位应该是针对二进制而言的,所以不能超过32位(其实是31位,第31位是符号位,也就是用0表示正数,用1表示负数)。


待会我给你写个可以得到结果的。


== 割 ==

#include <stdio.h>
// n2 > n1, [n1, n2]
int clip(int n, int n1, int n2) {
n1 -= 1;
int mask = ((1 << (n2 - n1)) - 1) << n1;
return (n & mask) >> n1;
}
int main() {
int n, n1, n2;
scanf("%d %d %d", &n, &n1, &n2);
printf("%o\n", clip(n, n1, n2));
return 0;
}


比如n = 123, n1 = 2, n2 = 4, 按照我上面说的应该是101,所以就会输出5。


你看看有没有问题。

第2个回答  2014-01-20
short int 范围为-(2^15)~(2^15-1),
当1001左移后,其实变成了负数,这个时候右移的过程中,补码最左位始终为1,即正负号不变;试试把左移的数据保存到usigned追问

我试了把n和函数change都定义为unsigned short int,但结果都没改变啊。

追答

负数的右移:负数右移的话,由于要保持它是负数,所以负数的二进制的右边补1。如果一直右移的话,最后就就变成0xFFFFFFFF 即-1

看来右移的过程中只要第一位是1,那么右移后的补位都是1,即使定义的是unsigned也没有用;看来你要用其他方法了,右移后 & 0x0007吧 (保留3为用0x7, 保留4为0xF...)

追问

可能昨天没改对,今天把n改为unsigned short int 型就可以了。
那你知道没改之前的程序,即有符号n,在获得123数据左移又右移之后变成1111 1111 1111 1001对吧,这个数就是十进制的-7,这我明白,但他为什么用八进制打印是37777777771,我觉的应该是177771才对吧,难道它变成了32位的?我定义的是short int 啊,不是两字节16位吗?

追答

short int到底占多少个字节其实没有特别规定,你打印一下sizeof(short int)大小看看,可能你的编译器也是4字节

第3个回答  2014-01-21
移位只对 符号整型操作,你定义带符号。
只需要把,传递的变量和函数返回值,n改为无符号,
第4个回答  2014-01-21
越界了,建议把数据类型定义成long

c语言中,如何实现位运算?
c语言:取整型变量x中的第p位开始的n个bit位,可以采用位运算的方法。先向左移位,丢弃前面不需要的位,再通过向后移位,丢弃后面不需要的位,最后再向左移位到原来的位置,就可以了。1\/\/num&(num-1)=(1111)&(1110)=(1110)2\/\/num&(num-1)=(1110)&(1101)=(1100)3\/\/num&(num-1)=(11...

c语言位运算问题?
c语言位运算问题解答:要解答这个问题我们先来看一个例子,代码如下图一,图中右边是问题中得到代码,左边是这段代码的汇编指令。两种情况的不同点详细说明如下:第一种情况:printf("%d",2>>64);由图中的汇编代码可以看出,如果两个数都是常数的情况下,代码中是不含对应的汇编指令的,因为编译器...

c语言的位运算疑惑
1:040 是八进制的表示。换成十进制是 4*8+0*1=32 2:ASCII编码表中 32表示的是空格符号。 char中寸的是ASCII编码,所以是32 3:位移运算:>>表示右移位 我以8为例。8的二进制是1000, 8>>1对应的二进制形式就是1000——0100看到变化了没有。所以右移位相当于这个数除2 左移位你看看 010...

c语言位运算
C语言中的位运算符用于操作二进制位。这些运算符直接对整数的二进制位进行操作,是低级语言操作的重要组成部分。它们对于优化程序性能、实现特定功能非常关键。具体的位运算符 1. 位移运算符:这两个运算符用于将二进制位向左或向右移动指定的位数。例如,`x << 2`表示将x的二进制表示向左移动两位,...

C语言位运算取反问题?
首先你输出是肯定用的 printf("%d",~a).int类型数据是有范围的 -32768~32767 [100]原=0000 0000 0110 0100 取反后为1111 1111 1001 1011 这个数值已远远超出了范围,发生溢出.但是这个数值是-101的补码,而计算机数字都是按补码存储的,所以他输出了-101.你放成ld,数值又不同....

C语言——位运算
本文将介绍C语言中的位运算,它允许程序员直接操作二进制位。二进制位,或“位”,仅包含0或1。在计算机中,数据以二进制形式表示,执行的指令亦是如此。计算机内部的数据以补码形式存储。这意味着,对于数字的二进制表示,最左侧的位(符号位)指示数字是正还是负。位运算包括:取反运算、左移运算、...

C语言中位运算符问题 这句话怎么解释啊
这句话的理解有这样一个基础,那就是右移n位相当于除以2的n次方,而这个基础就是对于无符号数来说的。比如无符号数8,如果用8位二进制表示,就是二进制的0000 1000,右移0位,也就是不移动,等于8,就等于8除以1,也就是8除以2的0次方;右移1位,0000 0100 ,等于4,就等于8除以2,也...

C语言——位运算
C语言中,位运算是一种独特且强大的功能,它直接作用于二进制位级,对数据进行操作。位运算符包括按位取反(~)、左移(<>)、按位与(&)、按位或(|)和按位异或(^)。以下是这些运算符的简介和示例:1. 按位取反(~):单目运算符,将运算数所有位取反,如无符号字符a=18,~a的结果...

C语言问题,在位运算中,操作数每右移一位,其结果相当于什么?若左移1位...
1、右移,除以2右移n位除以2的n次方;右移的概念和左移相反,就是往右边挪动若干位,运算符是>>;右移对符号位的处理和左移不同,对于有符号整数来说,比如int类型,右移会保持符号位不变,例如:inti=0x80000000;i=i>>1;\/\/i的值不会变成0x40000000,而会变成0xc0000000 2、左移,乘以2...

C语言位运算题目
一、位运算符c语言提供了六种位运算符:&按位与 |按位或 ^按位异或 ~取反 <<左移 >>右移 1.按位与运算按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。例如:9&5可写算式...

相似回答