Java基础类型为什么不提供无符号数与位掩码操作陷阱

一个数值,特别是整数,在有无符号的条件下,能表示的数值范围不同。

在C/C++中,数据都是有符号之分的,但这也造成了一个严重的问题,看以下的代码:

char c = 0x80;
int n = c;
printf("%x", n);


即使是字符类型,也是有符号的,因此当c被赋值为0x80的时候,它直接代表-128

c向n做类型转换,n也是有符号的,因此c对n而言就是-128,n也被赋值为-128

但是n的2进制数据肯定不是0x00 00 00 80,而是:

0xff ff ff 80

这是在int类型中表示-128的二进制数据。

一般来说,有符号向有符号的转换,数值上不会出现问题。除非你非要将一个超过表示范围的有符号数向低级的类型转换(int --> char)


但是有符号数和无符号之间转换就能出现问题了

char c = 0x80;
unsigned int n = c;
printf("%x", n);

上面哪个例子改了改,变成了用一个无符号数n来取得c的数值。

c是-128,那么c转成无符号的int后是什么呢?肯定不是128,不是去掉符号那么简单

那么会不会是先转成无符号char 然后提升为unsigned int呢?即n是

0x00 00 00 80

VC 2010上的实验结果表明,

n依然是

0xff ff ff 80

这说明了至少在VC 2010上,char 还是转成了有符号的int,只是n在数值上按照无符号的处理罢了。


有无符号的问题是让很多程序员头疼的一大问题。

因此Java就干脆说我们都有符号好了,这样你数值转化上就不用那么头疼。只要不超过表示范围,就不会造成数据理解上的问题。

但是Java这么搞也有一个问题:位掩码的问题


很多程序会用一个数据位来表示一种状态。

例如:用户在系统中具有很多权限,于是可以用一个位而不是一个整数来标识用户在系统中的某个权限是否开启。

这样,应用程序就会为权限定义一些掩码

比如下面几个掩码就定义了四种权限


#define CREATE_FILE   0x00000001

#define DELEET_FILE 0x00000002

#define READ_FILE 0x00000004

#define WRITE_FILE 0x00000008


这样,当一个用户的权限信息输入了的时候,就可以通过


DELEET_FILE & nPrivInput

来判断用户的权限数据nPrivInput是否具有删除文件的权限。

一般来说,权限信息没有什么有没有符号之分,因此都是用无符号数来表示。


这样,如果程序员考虑节省一点点内存,就能用

byte nPrivInput
来表示输入,这样,nPrivInput即使和以上这些宏操作的时候需要转化为 unsigned int 也不会有问题,其表示0x FF FF的时候转成整数也只是变成了0x 00 00 FF FF,不会变成 0x FF FF FF FF,相应于不会开启本没有赋予它的权限。

但是,如果nPrivInput是用有符号数实现的,则就有问题了

比如,程序员错误的写成了:

char nPrivInput = 0x80 //代表用户某一权限被启动

nPrivInput & 0x10 00 00 00时会出现什么情况呢?

nPrivInput会被转化为整数,变成0xff ff ff 80

因此

nPrivInput & 0x10 00 00 00 就会发现该权限被赋予了,造成程序错误。


因此,在JAVA上,如果要用掩码实现这类功能,由于JAVA的所有基础类型都是有符号的,因此切记

掩码的长度最好和用于存储待操作数据的变量一致。

即如果待操作数据的变量是个int,则掩码最好是4个字节,不要是8个字节这样不会造成问题。

而且,待操作数据在传递过程中,最好不要进行类型转换。

例如,待操作数据是个int, 则最好在数据传递到掩码运算时不要经过类型转换,否则将可能造成程序错误

最后,也是最重要的,在进行操作的时候,清晰类型转换的操作过程能够减少很多“加班”的时间







你可能感兴趣的:(那些年我们躺着中枪的幺蛾子,诚不欺我大JAVA)