C语言的补码表示和unsigned及signed的转换

时间:2023-01-13 23:17:17

这东西实际编程时一直无视的,范围小了就换个大点的表示形式,但是总觉得基础知识还是掌握得好,免得到时候用移位运算或类型转换或笔试题时要花时间想。

C语言的基本类型有char、int、float、double,另外还有说明符long、short、signed和unsigned。

首先要注意在不同操作系统中类型大小不一样,下面的情况只是考虑其中一种情况。

int和char均默认为signed,二进制的最高一位来表示符号,0为正1为负。

假如short int是16位,由于第1位表示正负,所以只剩15位表示实际数值,范围为-2^15到2^15-1

举例,按照原码表示:

0000 0000 0000 0101表示5

1000 0000 0000 0101表示-5

反码就是符号位不变,数值位取反,比如5就表示为0111 1111 1111 1010

但是这样问题来了,1000 0000 0000 0000跟0000 0000 0000 0000表示的都是0,这样0就有2种编码方式。

所以C语言采取了补码表示,1000 0000 0000 0000表示的是-2^15而非0。

补码:1、对于正数,补码与原码相同;2、对于负数,数值位的绝对值取反后在最低位加1。

PS:负数转整数也是取反后最低位加1(不是减1)

因此,C语言中是用表示-5的是1111 1111 1111 1011

那么对负整数逐次进行自加运算得到结果如下

-4  1111 1111 1111 1100

-3  1111 1111 1111 1101

-2  1111 1111 1111 1110

-1  1111 1111 1111 1111

于是-1再自加后所有位数全部变为0,0的表示形式就变成了0000 0000 0000 0000,表示0的只有一种形式。

C语言支持移位运算,即将数据看成二进制数,对其向左或向右移动若干位。

逻辑移位:移出去的位丢弃,空位补0

算术移位:移出去的位丢弃,空位补符号位(只有当有符号数做右移运算时才是算术移位)

0000 0101向左移2位(即5<<2)后变成 0001 01??,?处补0,所以结果是0001 0100,为20.

1111 1011向左移2位(即-5<<2)后变成1110 11??,?处补0,所以结果是1110 1100,按照补码规则,为正数0001 0011的相反数加1,即-(19+1)=-20

所以左移很简单,可以i << j可以替代乘法运算i*2j,运算效率更高。

要注意的是,虽然一般不会用到,但是左移位数超过该数值类型最大位数时,编译器会用位数求余,所以这就跟具体类型大小有关。

0010 1001向右移2位(即41>>2)后变成??00 1010,正数?处补0,所以结果是0000 1010,为10。

1101 0111向右移2位(即-41>>2)后变成了??11 0101,负数?处补1,所以结果是1111 0101,为正数0000 1010的相反数加1,即-(10+1)=-11

可以看出绝对值相同的正数和负数右移同样位数后得出的结果并不一致,i>>j并不能等价于i/2j!-41/4的结果是-10!

最后谈谈unsigned转signed,以char为例。

char在计算机内部是用一个字节的二进制来表示的,这里假定默认为signed,表示范围为-128到127。

对于char c = 128; c的二进制表示为1000 0000,如果转换成int输出是-127。

char转换成short int并不是说位数增加了,而是把它当成short int来解释,因此c还是1000 0000,表示的是-127,而不会因为转型为int就变成了0000 0000 1000 0000

看下面一段代码,signed转unsigned

int _tmain(int argc, _TCHAR* argv[])
{
char c = 128;
unsigned char cu = c;
short int i = cu;
cout << i;
return 0;
}

把c转换成unsigned char后,再转换成short int,那么输出的就是128,转型后还是1000 0000,但是按照unsigned的解释,最高位不再是符号位,而是数值位,所以结果就是2^8=128。

好了,再看下面一段代码,unsigned转signed

int _tmain(int argc, _TCHAR* argv[])
{
unsigned char cu = 255;
char c = cu;
short int i = c;
cout << i;
return 0;
}

255的unsigned表示为 1111 1111,转换为signed后,符号位1代表是负数,数值位转换成十进制后是127,按照补码的定义结果为-1。

以前用OpenCV处理图像时,经常被绕住,因为IplImage*的ImageData是char表示的,而处理图像时一般都转化成了unsigned char,回顾了补码的概念后那么下面这个对应就好理解了。

数值区间 [0,127] [-128,-1]
char x x
unsigned char x 256+x

C语言的补码表示和unsigned及signed的转换的更多相关文章

  1. unsigned 和 signed

    http://www.cnblogs.com/stonehat/archive/2011/10/14/2212141.html http://m.blog.csdn.net/blog/u0100862 ...

  2. c语言中的unsigned 和 signed

    我们来一起看下,C语言中,对于Integer Type(整数形式)的unsigned与signed两种形式的区别,以及在内存中的存储方式是如何的 Integer type(整数形式)是C语言中的基本数 ...

  3. 程序员之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)

    主要内容:无符号和有符号之间转换.两数相加溢出后数值计算 #include <stdio.h> /* 这个函数存在潜在漏洞 */ float sum_elements(float a[], ...

  4. C&plus;&plus; char&comma; unsigned char&comma; signed char

    C语言中的 char, unsigned char, signed char 一.他们是什么? signed char是有符号的,但是unsigned char没有符号,两者在存储上没有任何区别都是8 ...

  5. Swift3&period;0语言教程字符串与URL的数据转换与*转换

    Swift3.0语言教程字符串与URL的数据转换与*转换 Swift3.0语言教程字符串与URL的数据转换 Swift3.0语言教程字符串与URL的数据转换与*转换,字符串中的字符永久保存除了可以 ...

  6. C&num; 语言规范&lowbar;版本5&period;0 &lpar;第6章 转换&rpar;

    1. 转换 转换(conversion) 使表达式可以被视为一种特定类型.转换可导致将给定类型的表达式视为具有不同的类型,或其可导致没有类型的表达式获得一种类型.转换可以是隐式的 (implicit) ...

  7. 【转】mysql 中int类型字段unsigned和signed的区别

    转自https://www.cnblogs.com/wangzhongqiu/p/6424827.html 用法: mysql> CREATE TABLE t ( a INT UNSIGNED, ...

  8. mysql 中int类型字段unsigned和signed的探索

    转自:http://www.0791quanquan.com/news_keji/topic_816453/ 探索一:正负数问题 拿tinyint字段来举例,unsigned后,字段的取值范围是0-2 ...

  9. Docs-&period;NET-C&num;-指南-语言参考-关键字-值类型:内置数值转换

    ylbtech-Docs-.NET-C#-指南-语言参考-关键字-值类型:内置数值转换 1.返回顶部 1. 内置数值转换(C# 参考) 2019/10/22 C# 提供了一组整型和浮点数值类型. 任何 ...

随机推荐

  1. PHP动态实例化对象并向构造函数传递参数

    在框架开发,模块化开发等场合,我们可能有一种需求,那就是在PHP运行时动态实例化对象. 什么是动态实例化对象呢?我们先来看一下PHP有一种变量函数(可变函数)的概念,例如如下代码: function ...

  2. c&plus;&plus; boost 汉字和模式串混用的例子

    *=============================================================== * Copyright (C) All rights reserved ...

  3. (转)javaScript插件开发

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

  4. oracle 学习笔记 复制表结构

    1.复制表结构以及数据 create table d_table_name as select * from s_table_name;  ---注意并不会创建索引 2.只复制表结构 create t ...

  5. 自定义cell 自适应高度

    #pragma mark - 动态计算cell高度 //计算 返回 文本高度 + (CGFloat)calsLabelHeightWithContact:(Contacts *)contact { / ...

  6. 常见tcp端口

    TCP端口 7 = 回显 9 = 丢弃 11 = 在线用户 13 = 时间服务 15 = 网络状态 17 = 每日引用 18 = 消息发送 19 = 字符发生器 20 = ftp数据 21 = 文件传 ...

  7. C&plus;&plus;中的继承(3)作用域与重定义,赋值兼容规则

    作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A& ...

  8. Can you find it&quest;

    Can you find it? Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/10000 K (Java/Others) T ...

  9. 数据库中插入数据时发生ora-00984错误

    操作Oracle数据库,插入数据时显示:ORA-00984列在此处不允许错误,如下图所示: 出现的原因是由于,在插入字符或字符串型字段时.如果插入的数据是纯数字,则不会有错误:如果出现字符,则会报OR ...

  10. 2019&sol;1&period;7 js面向对象笔记

    面向对象 1.构造函数里的属性怎么看?看this,谁前面有this谁就是属性. num不是属性,是私有作用域下的私有变量. 2.如何查找面向对象中的this 1.构造函数的this指向实例对象 2.如 ...