位和位运算
- C语言中数据的表示方法
- 各种数据类型可表示的数值范围
- 位和CHAR_BIT
- sizeof运算符
- 整型的内部表示
- 无符号整数的内部表示
- 有符号整数的内部表示
- 位运算
- 位运算符
- 位与运算
- 位或运算
- 位异或运算
- 位取反运算
- 位左移运算符
- 位右移运算符
- 逻辑位移与算术位移
C语言中数据的表示方法
各种数据类型可表示的数值范围
C语言编译器在<limits.h>头文件中以宏定义的形式定义了字符型以及其他整型所能表示的数值的最大值和最小值。
下面来看看在VC++环境下的各数据类型所能表示的数值范围。
#include <stdio.h>
#include <limits.h>
int main(void)
{
puts("该环境下各字符型、整型数值的范围:");
printf("char :%d~%d\n",CHAR_MIN,CHAR_MAX);
printf("signed char :%d~%d\n",SCHAR_MIN,SCHAR_MAX);
printf("unsigned char :%d~%d\n",0,UCHAR_MAX);
printf("short :%d~%d\n",SHRT_MIN,SHRT_MAX);
printf("int :%d~%d\n",INT_MIN,INT_MAX);
printf("long :%d~%d\n",LONG_MIN,LONG_MAX);
printf("unsigned short :%d~%d\n",0,USHRT_MAX);
printf("unsigned int :%u~%u\n",0,UINT_MAX);
printf("unsigned long :%lu~%lu\n",0,ULONG_MAX);
return 0;
}
位和CHAR_BIT
计算机中的所有数据都是用0和1(即“位”)的组合来表示的。
C语言中“位”(bit)的定义如下:
- “位”是具有大量内存空间的运行环境的数据存储单元,可保存具有两种取值的对象。
- “位”可取两种值,其中一种是0。将位设为0以外的值,称为“设置位”。
根据编译器的不同,char型
在内存上占据的位数
也不同。该位数作为对象式宏CHAR_BIT
定义在<limits.h>中。
char型的位数因编译器
而定,至少为8
。
能够用字符型表示的数值范围
是依附于CHAR_BIT
的。
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("char 型在内存上占据的位数:%d\n",CHAR_BIT);
return 0;
}
char型的内部:
sizeof运算符
C语言中将表示字符的char型的长度
定义为1
。(char的长度可以通过计算机硬件的位数来确定。在32位系统中,char占用1个字节(8位);在64位系统中,char也仍然占用1个字节(8位)。这意味着char的长度不会随着计算机系统的升级而改变。)
通过使用sizeof运算符
(sizeof operator),可以判断出包括chai型在内的所有数据类型的长度
。该运算符以字节(bite)
为单位。
下面我们来使用sizeof运算符,显示字符型和整型的长度。
#include <stdio.h>
int main(void)
{
printf("sizeof(char)=%d\n",sizeof(char));
printf("sizeof(short)=%d\n",sizeof(short));
printf("sizeof(int)=%d\n",sizeof(int));
printf("sizeof(long)=%d\n",sizeof(long));
printf("sizeof(unsigned char)=%u\n",(unsigned)sizeof(char));
printf("sizeof(unsigned short)=%u\n",(unsigned)sizeof(short));
printf("sizeof(unsigned int)=%u\n",(unsigned)sizeof(int));
printf("sizeof(unsigned long)=%u\n",(unsigned)sizeof(long));
return 0;
}
- 程序的运行结果因编译器和编译环境的不同而不同。但
sizeof(char)
必为1
。` - 各种数据类型的
有符号型
和无符号型
的长度相同。例如,sizeof(short)和sizeof(unsigned short)相等,sizeof(long)和sizeof(unsigned long)相等。 - short 、int、long具有如下关系:
sizeof(short)≤sizeof(int)≤sizeof(long)
即右侧的数据类型和左侧的数据类型相等,或者大于左侧的数据类型。
整型的内部表示
整型内部的位表示使用的是纯二进制计数法
(pure binary numeration system)。但对于构成整型的位序列的解释,无符号类型
和有符号类型
是完全不同的。
无符号整数的内部表示
无符号整数的数值在计算机内部是以二进制数
来表示的,该二进制数与各二进制位一一对应。例如十进制数25用二进制数表示如下:
25用二进制数表示是11001,高位补0后表示为0000000000011001。
以16位为例,无符号整数的最小值为0,即0000 0000 0000 0000,最大值为65535,即1111 1111 1111 1111。
有符号整数的内部表示
当存储有符号数时,最高位为符号位
(1表示负数,0表示非负数),其余位是数据位
。
计算机中有符号整数的存储是以补码
形式存储的。
一个整数有以下三种编码。
原码
十进制整数数码化为原码的方法是首先把十进制整数转换为二进制,然后在高位用0补足15位,最后添上符号位。
反码
对整数而言,原码即为反码,对负数而言,反码是将原码中除符号位之外的其余位依次取反。
补码
对整数而言,原码即为补码。对负数而言,补码是在反码的基础上加1。在求补码的过程中,符号位不发生变化,当数据的最高位有进位时,舍弃进位。
补码的运算法则如下:
位运算
位运算符
C语言提供了六种运算符:
&
位与运算符
|
位或运算符
^
位异或运算符
~
位取反运算符(单目运算符)
<<
位左移运算符
>>
位右移运算符
注意,位运算的对象只能是整型和字符型,不能是浮点型数据。运算结果是整形数据。
位与运算
&
运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位与运算,当两个相应位都为1时,运算结果的相应位也为1;否则,运算结果的相应位为0。
位或运算
|
运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位或运算,当两个相应位都为0时,运算结果的相应位也为0,否则运算结果的相应位为1。
位异或运算
^
运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位异或运算,当两个相应位相同时,运算结果的相应位为0,否则运算结果的相应位为1。
位取反运算
~
运算的含义是对参与运算的运算对象的机器码按二进制方式对相应位进行位取反运算,1变0,0变1。
注: &
|
和~
运算符的功能和&&
||
和 !
运算符功能相似,但要注意它们的区别。
&&
||
和 !
会根据非零为真,零为假的运算规则对操作数进行逻辑运算。
&
|
和~
会根据1为真,0为假的运算规则对操作数的二进制位进行逻辑运算。
例如:
表达式 3 & -1
的值计算如下:
而表达式 3 && -1
的值为1.
位左移运算符
<<
运算的含义是对参与运算的运算对象的机器码按规定的移位数进行左移。<<
运算符构成的表达式一般格式为a<<n
,其中a是需要移位的数据,n是移位的位数。在移位的过程中,高位移除的位舍弃,低位左移后补0。
例如:
表达式a<<1的运算如下:(a=3)
这里需要注意的是,a<<1后,a的值不变。
以上述为例,通过左移a<<1的值为6,是原来的2倍。其实不难理解,以十进指数为例,假如将198进行左移,低位补0后,变成了1980,是原来的10倍。而在二进制中,若向左移动n位,那么a<<n就会变成原来的2的n次方。
位右移运算符
>>
运算的含义是对参与运算的运算对象的机器码按规定的移位数进行右移。>>
运算符构成的表达式一般格式为a>>n
,其中a是需要移位的数据,n是移位的位数。
例如:
表达式a>>1(a=3)的运算如下:
同样的,a>>1后,a的值不变。
通过右移,a>>1的值变为原来的二分之一。在二进制中,若向右移动n位,则会变为2的n次方分之一。(不一定是恰好是整数倍,可能会有余数,但是商的结果是。)
逻辑位移与算术位移
对于右位移运算,可以分为两种,逻辑位移和算术位移。
逻辑位移
逻辑移位不考虑符号位,所有二进制位都进行位移。(包含符号位在内的所有位都进行位移)
这样对于负数而言,进行右位移运算后,会变成非负数。
例b>>4(b=-16)
位移为-16,进行位移运算,b>>4的值为2的12次-1。
算术位移
算术位移会保留最高位的符号位,只对除了符号位之外的其他位进行位移。
对于位移之后的空位用符号位的值进行填充。位移前后的符号不变,即负数还是负数,正数还是非负数。
以上述b>>4(b=16)为例
b>>4的值为-1。