计算机中储存和处理的信息是以二进制信号表示的。单个的位不是是很实用,而将这些位 组合在一起,加上某种解释,即给不同的可能位模式赋予含义,我们就行表示怎样有限集合的元素,即实现各种数据结构。计算机中使用8位的块称之为字节作为最小的可寻址的存储器单位,机器级程序将存储器视为一个很大的字节数组,称为虚拟存储器。存储器的每一个字节都有一个唯一的数字来标识,称为地址,全部可能地址的集合称为虚拟地址空间

c语言中的指针,指针的值为某个存储块的第一个字节的虚拟地址。C编译器将每一个指针和类型信息结合起来,依据指针值的类型也就是声明的指针类型,来生成不同的机器级代码来訪问储存在指针所指向位置出的值每一个程序对象能够简单的视为一个字节块,而程序本身就是一个字节序列。

字长,32位系统为4个字节,64位系统为8个字节,对于32位字长时,其能表示的虚拟地址范围为0 - 2^32-1 ,即虚拟地址空间最大为4GB。

大端法:最高有效字节在低地址位。

小端法:最高有效字节在高地址位。

一般系统都使用的是大端法。

C中主要的位运算:

^异或, 1 ^ 0 = 1    ,     0 ^ 1 = 1,      0 ^ 0 = 0,      1 ^ 1 =  1   .

& 且   |或   ~取反

<< n 左移 n   位     >>   n   右移n位

c中的右移有两种,逻辑右移和算术右移,逻辑右移即在左端补0,而算术右移在左端不最高有效位的值。一般对于有符号数进行的是算术右移,

java中使用>>表示算术右移,而使用>>>表示逻辑右移。

位运算操作符的优先级都低于 加减 号, 所以 在算式中 一般都要用括号 括起来。

对位运算的一个常见使用方法是实现掩码运算。掩码就是指从字节中选出一定位的集合。

计算机系统中有三种重要的数字表示,无符号(unsigned)编码,仅仅能表示非负的数,补码(two's-complement)编码,用来表示有符号整数,浮点数(float-point)编码,表示实数的科学计数发的二进制版本号。仅仅有C系语言有无符号数这个概念,但我觉得无符号数的存在是一种长处。

这里讨论两种编码,无符号和补码。

无符号数的编码即直接将二进制数据转换为10进制,就能够得到结果。其最大值为 2 ^ w - 1,w为其位数,最小值为0.

补码:最高有效位解释或为负权,即 - 2 ^w ,然后将全部位乘以权值得到结果。最高有效位即为符号位。最大值为 2 ^(w-1)-1,最小值为 - 2^w.补码的范围是不正确称的。

因为不同机器上的数据类型可能有不同的取值范围,如long,在32位系统中为4个字节,但在64位系统中为8个字节。所以一般使用在stdint.h中定义的数据类型intN_t和unintN_t,来声明N位的有符号数和无符号数,则会使程序在不同系统中都能够正确执行。N一般去8,16,32,64。

有符号数和无符号数之间的转换:

程序读取不同类型时,仅仅是对存储器上的信息以不同的方式进行解释,而C语言进行强制转换时,也仅仅是改变了其解释存储器上位信息的方式,并没有改变存储器上的信息本身。

所以相同位长的无符号数和有符号数直接的转换,不改变底层的位信息,仅仅是换了一种解释的方法来解释这些位。如对无符号的int 4 294 967 295转换为有符号的int就是 -1,而有符号的int 的-1转换为无符号的int 就是4 294 967 295。

当一个运算中 一个运算数为有符号,一个运算数为无符号数,C语言会隐式地将有符号数强制类型转换为无符号数,,然后运行两个无符号数之间的运算。对于标准的运算来说,这样做不会出错。如 c = a + b, 当中c和a为有符号int,a为-1,b为无符号int为1,则运算时,将a转换为无符号数,也就是 4 294 967 295,然后加b,应得到的是4 294 967 296,但在位级上,因为最高位的1超过范围而溢出,仅仅剩下32个0,则最后c的结果为0。能够看出,这里对普通的运算没有影响。

但在一些关系表达式中,则会出错。如 -1 < 0u。u表示无符号数,这里将-1转换为无符号的int后,值为4 294 967 295,肯定是比0要大的,然后就出错了。

在不同字长的整数之间进行转换,须要进行为的扩展和截断。

扩展:

无符号数扩展使用,零扩展:在表示的开头加入0。

有符号数扩展使用,符号扩展:在表示中加入最高有效位的值的副本。即符号位为1时,加入若干个1。

有符号的负数扩展时,前面加入1不会对最后的数值有影响,假定扩展前为w位,扩展后为v位,扩展前的值为-i,则有扩展前除去最高位,剩下为表示的整数为j = 2^w - i,则扩展后,从符号位到原来符号位,即除去j表示数据的部分的剩余部分表示的值为: - 2 ^(v-1) + 2^(v-2)+...+2^w ,则扩展后表示的值为  - 2 ^(v-1) + 2^(v-2)+...+2^w + 2 ^w-- i.则前面的数都能够消去,即得到最后结果为-i。

.C中同一时候进行有无符号转换和不同字长的数据转换时,想转换不同字长的数据类型,即先进行扩展或者截取,然后在使用有符号或者符号的方式来解释数据。

截断:

截取时即舍去高n位就可以。

整数运算:

无符号数的加法,会导致结果大于数据类型的范围,则无符号的运算事实上是一种模运算,利用溢出机制,实现计算和模2^w。

算术运算溢出,指完整的整数结果不能放到数据类型的字长限制中去。推断两个数相加,如 c = a + b,是否发生溢出,仅仅要推断 c是否 小于a或者b就可以,由于a或者b肯定是小于2^w。

补码的加法:

两个有符号数的w位补码之和与无符号数之和有全然相同的位级表示,计算机使用相同的机器指令来运行无符号或有符号的加法。如之前进行的分析: c = a + b, 当中c和a为有符号int,a为-1,b为无符号int为1,则运算时,将a转换为无符号数,也就是 4 294 967 295,然后加b,应得到的是4 294 967 296,但在位级上,因为最高位的1超过范围而溢出,仅仅剩下32个0,则最后c的结果为0。

假设将这里的b也看作是有符号数,其结果依旧如此且正确。

所以,我们能够理解为,补码的加法是 先将其转换为无符号数,然后相加,得到的结果在转换为有符号数。

这里有溢出,正溢出和负溢出。

正溢出:得到的结果应该位于2^(w-1)    —— 2 ^w  - 1,但使用补码转换为有符号数后是在 0 —— - 2 ^ (w-1)这个范围内。

负溢出:得到的结果应该在-2^w ——  -2^(w-1),可是因为溢出,结果在 0 —— 2^(w-1) -1上。

其它情况为正常。

补码的非:

即取负。对于 -2 ^(w-1)取非为 其本身。对于其它的值能够得到正确结果。

无符号的乘法:

即计算乘积后模 2^w。

补码的乘法:

补码乘积的范围在 -2^(2w-2) + 2^(w-1)    和 -2^(2w-2)之间。这里,对于无符号和补码的乘法运算,其位级表示依旧是一样的,所以对于补码的乘法是将其转换为无符号数,然后相乘,结果模2^w。这里对于运算的分析:

令x,y的无符号值为 a,b,其符号位值为 c,d。则 a = x + c * 2^w , b = y + d * 2 ^ w;

a * b % 2^w

= (  (x + c * 2^w  )*( y + d * 2 ^ w) )%2^w

= (x * y + (y *c + x*d + c*d * 2^w)* 2^w)% 2^w

= (x*y)% 2^w

计算机上的乘法指令相当慢,一般须要10个以上的时钟周期。编译器会使用一项重要的优化,用移位和加法运算和减法运算来取代乘以常数的乘法。如使用(x<<4)-(x<<1)来取代x*14。

计算机上的除法的速度就更加慢了,一般须要30个以上的时钟周期。除以2的幂能够通过右移操作进行,对于无符号是逻辑移位,对于补码进行算术移位。

c的基础 1. 无符号数和补码的更多相关文章

  1. C语言基础(5)-有符号数、无符号数、printf、大小端对齐

    1.有符号数和无符号数 有符号数就是最高位为符号位,0代表正数,1代表负数 无符号数最高位不是符号位,而就是数的一部分而已. 1011 1111 0000 1111 1111 0000 1011 10 ...

  2. C++有符号和无符号数的转换

    本文转自:http://www.94cto.com/index/Article/content/id/59973.html 1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题 ...

  3. C语言基础 (4) 原码反码补码与数据类型

    1.回顾 使用gcc编译代码 gcc hello.c -o hello windows下编译代码 C语言编译步骤: 预处理(头文件展开,干掉注释) gcc -E hello.c -o hello.i ...

  4. 关于有符号数和无符号数的转换 - C/C++

    转载自:http://www.94cto.com/index/Article/content/id/59973.html 1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题, ...

  5. C语言基础(4)-原码,反码,补码及sizeof关键字

    1. 原码 +7的原码是0000 0111 -7的原码是1000 0111 +0的原码是0000 0000 -0的原码是1000 0000 2. 反码 一个数如果值为正,那么反码和原码相同. 一个数如 ...

  6. C++中有符号/无符号数比较

    原创文章,欢迎阅读,禁止转载. 在我的程序中有如下代码编译被警告了 if(list.size()>msize){...} warning C4018: '<' : signed/unsig ...

  7. matlab和FPGA中无符号数和有符号数的转化(转)

    在FPGA 设计过程中经常会遇到关于数表示之间的转化问题,最常见的是无符号数和有符号数之间的转化问题.(1)在FPGA设计过程中,能够很直接的看出数字的位宽,但经常以无符号数的形式输出,在后继的处理中 ...

  8. 抢车位中的排名bug(比較使用了无符号数)

    昨天把这个发在了qzone,想来还是怪怪的,还是转过来不吧,纯当发现了一个虫子,玩笑一下.只是csdn如今不能贴图,挺郁闷的,原文在http://user.qzone.qq.com/110907073 ...

  9. 深入理解计算机系统(2.5)------C语言中的有符号数和无符号数以及扩展和截断数字

    上一篇博客我们讲解了计算机中整数的表示,包括无符号编码和补码编码,以及它们之间的互相转换,个人觉得那是非常重要的知识要点.这篇博客我们将介绍C语言中的有符号数和无符号数以及扩展和截断数字. 1.C语言 ...

随机推荐

  1. POJ 2635 The Embarrassed Cryptographer 大数模

    题目: http://poj.org/problem?id=2635 利用同余模定理大数拆分取模,但是耗时,需要转化为高进制,这样位数少,循环少,这里转化为1000进制的,如果转化为10000进制,需 ...

  2. asp.net core 认证及简单集群

    众所周知,在Asp.net WebAPI中,认证是通过AuthenticationFilter过滤器实现的,我们通常的做法是自定义AuthenticationFilter,实现认证逻辑,认证通过,继续 ...

  3. nginx处理静态资源的配置

    修改nginx.conf文件,用于nginx处理静态资源. 主要配置如下(在server配置中加入location配置即可): server { listen 80; server_name 123. ...

  4. zImage和uImage的区别

    http://blog.csdn.net/maojudong/article/details/4178118 zImage和uImage的区别 一.vmlinuz vmlinuz是可引导的.压缩的内核 ...

  5. [转贴]JAVA 百度地图SDK地图学习——实现定位功能

    之前已经完成了百度地图SDK和百度定位SDK的配置. http://my.oschina.net/u/1051634/blog/180880 实现百度定位的功能,最好仔细看看官方的文档,看了好几次才有 ...

  6. 【简译】jQuery对象的奥秘:基础介绍

    本文翻译自此文章 你有没有遇到过类似$(".cta").click(function(){})这样的JavaScript代码并且在想“$('#x')是什么”?如果这些对你想天书一样 ...

  7. Android 拖动条(SeekBar)实例 附完整demo项目代码

    1.拖动条的事件 实现SeekBar.OnSeekBarChangeListener接口.需要监听三个事件:数值改变(onProgressChanged)开始拖动(onStartTrackingTou ...

  8. 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique

    2016-10-09 23:14:43.177 DEBUG [restartedMain][org.springframework.core.type.classreading.AnnotationA ...

  9. 《大数据Spark企业级实战 》

    基本信息 作者: Spark亚太研究院   王家林 丛书名:决胜大数据时代Spark全系列书籍 出版社:电子工业出版社 ISBN:9787121247446 上架时间:2015-1-6 出版日期:20 ...

  10. HDOJ--1698

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...