信息的表示和处理(2)

2.1.10 C语言中的移位运算

对于x = [x3, x2, x1, x0], x << 2 得到的结果是 [x1, x0, 0, 0]. 右移位运算分为两种, 逻辑右移和算术右移, 逻辑右移是指右移K位, 左端补上K个0, 而算术右移是指左端补上K的x3(最高有效位).

实际上, C语言标准并没有明确定义应该使用哪种类型的右移. 对于无符号数, 右移必须是逻辑的, 对于有符号数则存在争议. (但事实上几乎所以的编译器/ 机器组合都会对有符号数据使用算术右移.)

当移位数量足够大时 : 比如 w >> k, w是32位数, 而k恰好大于或等于32, 其实结果是未定义的(C语言标准并没有对这种情况进行规定)... 许多机器上会用 k mod 位数, 也就是如果k是32, 就相当于不移动, k是33, 就移动1位... 练习题很简单就不写了...

2.2 整数表示

2.2.1 整型数据类型

C语言中支持多种整数数据类型来表述有限范围的整数(char, short, int, long, long long), 这些不同类型所分配的字节数根据机器的字长和编译器不用可能会不太一样, C语言标准只是给出了一个这些数据类型必须保证的取值范围, 而并不做明确要求.

2.2.2 无符号数的编码

2.2.3 补码编码

实际上C语言标准并没有要求使用补发的形式来表示有符号正数, 但几乎所有的机器都是这么做的.  这里给出反码和原码的定义, 只做了解 :

2.2.4 有符号数和无符号数之间转换

总结下来我感觉有如下几点 :

1. 对于相同字长的有符号数和无符号数而言, 互相转化, 他们的位模式(也就是每一位的值)是不变的, 变得只是解释方式...

2. 对于同一个向量x, 如果我们计算B2U(x)-B2T(x), 会发现他们的0到w-2位的解释方式相同, 每一位的权相同, 互相抵消, 对于第w-1位, B2U(x)的权解释为2w-1而B2T(x)则正好相反解释为-2w-1,所以可以发现 B2U(x)-B2T(x) = 2* xw-1. 利用这个公式我们可以很轻松的得出结论 : T2U(x) = 2* xw-1 + x (x是补码值).

2.25 C语言中的有符号数和无符号数

C语言支持有符号数和无符号数, 虽然C语言标准未做规定, 但是大多数数字都默认是有符号的, 例如12345或者是0x1A2B这样的常理, 通常被认为是有符号的, 要创建无符号数通常要加上‘u‘ 或者 ‘U‘ 的后缀.

同时C语言对于有符号和无符号数的一些处理方式, 常常会导致一些奇怪的结果, 比如当同时将有符号数和无符号数进行运算时, 它默认转化有符号数为无符号数 : 那么在进行类似于 -1 < 0U 的比较时, 这个表达式的结果是0, 而按照正常逻辑应该是1.

另外一个指的注意的问题是在C语言的头文件 limits.h 的头文件中有如下一句话 :

#define INT_MIN (-INT_MAX -1) 为什么要这样麻烦的 -2147483647-1 而不是直接-2147483648呢? 原因就在于C语言编译器是识别到 2147483648 这个token的时候发现它的数值已经超过了int的范围, 已经默认将它识别为了long 或者 long long, 然后在进行取负操作的, 这样的话宏定义出来的值得类型不会是一个int, 所以不行.

2.26 扩展一个数字的位的表示

现在我们来考虑如何将较小的数字的位转换为一个更大的数据类型 (将较大的转化为较小的暂且不考虑), 对于无符号数而言, 只需要在扩展位上全部都补0就行了, 这种运算也称之为零扩展, 对于有符号数(补码数字)我们使用符号扩展, 也就是拓展位上全补上最高有效位的数字... 我们可以尝试着证明为什么这样做的结果是有效果的, 这里我们采用数学归纳法, 先证明对w位的补码数字, 扩展为w+1位时, 该补码数字值不变, 那么对于w+k, k为任意位时, 这个结论仍会成立...

另外还有一点值得注意的地方 : 如果我们将一个一个short转化为一个unsigned时, 结果其实是不确定的, 因为你会发现如果short先转化为unsigned short再转为unsigned int的结果和先转化为int 在转化为unsigned int 得出的结果不同, 而C语言标准规定的规则应该属于后者... 所以 :

1 #include <stdio.h>
2
3 int main(void){
4     short sx = -12345;
5     unsigned uy = sx;
6     printf("uy = %u\n", uy);  // 结果应该是这样 : uy = 4294954951 而不是 53191...7     return 0;8 }

2.27 截断数字

现在我们来考虑较大的数字转化为较小的数字(这里的大小指的是表示他们的数的位的大小而不是数字的实际大小), 例如对于w位的数字要截断为k位, 这时我们通常将w位数字的高w-k位舍去, 以这样的方式进行转换. 所以对于无符号数而言, 将它截断到k位就相当于是 x mod 2k, 当然对于有符号而言, 其实位值仍然是低k位的位值, 只是解释方式不同而已.

2.28 关于有符号数与无符号数的建议

所以碰到有符号数和无符号数隐式转换时要特别小心, 比如在练习题中 :

对于length = 0, 如果第14行不将其转换为int的话, length-1的值作为无符号数在这里可以认为无限大, 这个for会无限循环...

 1 #include<stdio.h>
 2
 3 float sum(float a[], unsigned length);
 4
 5 int main(void){
 6   float a[] = {1.2, 1.3, 1.4};
 7   printf("%f\n", sum(a, 0));
 8   printf("%u\n", 0u - 1);
 9 }
10
11 float sum(float a[], unsigned length){
12   int i = 0;
13   float re = 0;
14   for(; i <= (int)(length - 1); ++i){
15     re += a[i];
16   }
17
18   return re;
19 }

这里可能还是不太容易错, 书中的第二个例子非常好 :

如果我们想要写一个函数来判断两个字符串的长短, 极有可能写出下面这个longer() 的这种形式, 不幸的是这是错的, 因为strlen()的返回值是size_t类型, 这个类型实际上在<stdio.h> 是被定义成了unsigned int类型的, 单看strlen() 确实应该被定义成unsigned int类型, 毕竟它代表的是一个长度, 但是两者一结合就错了, 所以特别要小心...

 1 #include<stdio.h>
 2 #include<string.h>
 3
 4 int longer(char*s, char* t){
 5   return strlen(s) - strlen(t) > 0;
 6 }
 7
 8 int main(void){
 9   printf("%d\n", longer("abc", "ab"));
10   printf("%d\n", longer("a", "ab"));
11   printf("%d\n", 1u - 2u);
12   printf("%d\n", 1u - 2u > 1000);
13   printf("%d\n", 1u > -1);
14   printf("%d\n", 1u + 1 > 0);
15 }
时间: 2024-10-17 13:39:03

信息的表示和处理(2)的相关文章

基于位置信息的聚类算法介绍及模型选择

百度百科 聚类:将物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类.由聚类所生成的簇是一组数据对象的集合,这些对象与同一个簇中的对象彼此相似,与其他簇中的对象相异."物以类聚,人以群分",在自然科学和社会科学中,存在着大量的分类问题.聚类分析又称群分析,它是研究(样品或指标)分类问题的一种统计分析方法.聚类分析起源于分类学,但是聚类不等于分类.聚类与分类的不同在于,聚类所要求划分的类是未知的. 分类和聚类算法一直以来都是数据挖掘,机器学习领域的热门课题,因此产生了众多的

查看Linux系统版本信息

一.查看Linux内核版本命令(两种方法): 1.cat /proc/version [[email protected]CentOS home]# cat /proc/versionLinux version 2.6.32-431.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Nov 22 03:15:09 UTC 2013 2.uname -a [

java微信授权获取OPENID,ACCESS_TOKEN,用户信息

获取微信的openId流程 1.获取微信code 使用接口 : appId 是当前开发者的appId 不是用户的  path  是回调地址 这个链接是授权链接,当重定向这个链接的时候,会展示授权页,点击授权之后 跳入你path的请求接口    回调中带了一个参数code获取到就行 https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appId+"&redirect_uri="+path+"&

理解信息管理系统

1.信息与数据的区别是什么? 数据是记录客观事物,可鉴别的符号,而信息是具有关联性和目的性的结构化,组织化的数据.数据经过处理仍是数据,而信息经过加工可以形成知识.处理数据是为了便于更好的解释,只有经过解释,数据才有意义,才可以成为信息.可以说信息是经过加工以后,对客观世界产生影响的数据. 2.信息与知识的区别是什么? 信息是具有关联性和目的性的结构化,组织化的数据,知识是对信息的进一步加工和应用,是对事物内在规律和原理的认识.信息经过加工可以形成知识. 3.举一个同一主题不同级别的数据.信息.

调试信息的完成

gdb中-x是为了实现通过文件的初始化gdb GAS(gcc)(AT&T 语法),NASM(Intel 语法) 当boot loader 引导操作系统的时候,机器必须有如下的状态: EAX: 必须包含魔数OX2BADB002,这个值告诉操作系统目前它是由兼容的Multiboot 的boot loader 引导的. EBX: 必须包含boot loader 提供的多重引导信息结构(见3.3 节多重信息引导结构)的32位物理地址. CS: 必须是32 位的读/执行的代码段,偏移是0 以及界限是 0X

20145225 《信息安全系统设计基础》期中总结

期中总结 一.常用命令总结 man -k: 常用来搜索,结合管道使用.例句如下: man -k k1 | grep k2 | grep 2 搜索同时含有k1和k2,且属于系统调用. 最后的数字意味着帮助手册中的区段,man手册共有8个区段,最常用的是123,含义如下: 1.Linux 2.系统调用 3.c语言 但是当单独用man语句的时候,想查看其中的单独某个区段内的解释时,用法是这样的: man 3 printf 即查找c语言中printf的用法. grep -nr 这条语句可以用来查找关键字

20145336张子扬 《信息安全系统设计基础》第7周学习总结

20145336张子扬 <信息安全系统设计基础>第1周学习总结 教材学习内容总结 学习目标: 了解常见的存储技术(RAM.ROM.磁盘.固态硬盘等) 理解局部性原理 理解缓存思想 理解局部性原理和缓存思想在存储层次结构中的应用 高速缓存的原理和应用 三种常见存储技术:RAM.ROM和磁盘 随机访问存储器RAM分为静态RAM(SRAM)和动态RAM(DRAM) SRAM 用来作为高速缓存储存器,SRAM将每个位存储在一个双稳态的存储器单元里,每个单元是用一个六晶体管电路来实现的.它可以无限制地保

小白日记8:kali渗透测试之主动信息收集(二)三层发现:ping、traceroute、scapy、nmap、fping、Hping

三层发现 三层协议有:IP以及ICMP协议(internet管理协议).icmp的作用是用来实现intenet管理的,进行路径的发现,网路通信情况,或者目标主机的状态:在三层发现中主要使用icmp协议,arp协议属于二层协议,它是基于广播的,所以不可路由.而ICMP协议是可以路由的,理论上可以使用icmp协议发现全球的ip,如果没有边界防火墙(禁止icmp的探测包)进行过滤的话,对目标主机进行扫描,则会收到相应的响应,从而进行捕捉[有边界防火墙的现象比较普遍],但是三层发现的扫描速度也较二层要慢

20145317《信息安全系统设计基础》第六周学习总结(1)

20145317<信息安全系统设计基础>第六周学习总结(1) 第四章 处理器体系结构 指令体系结构:一个处理器支持的指令和指令的字节级编码 4.1Y86指令集体系结构 Y86:包括定义各种状态元素.指令集和它们的编码.一组编程规范和异常事件处理. Y86程序中的每条指令都会读取或修改处理器状态的某些部分.Y86具体包括:8个程序寄存器.3个条件码ZF\SF\OF.程序计数器(PC) Y86用虚拟地址引用存储器位置. 程序状态的最后一个部分是状态码Stat,它表明程序执行的总体状态. 注意:条件

20145239 《信息安全系统设计基础》第5周学习总结

20145239<信息安全系统设计基础>第5周学习总结 教材学习内容 x86寻址方式 DOS时代的平坦模式,不区分用户空间和内核空间,很不安全 8086的分段模式 IA32的带保护模式的平坦模式 机器级编程的两种抽象 -ISA(Instruction set architecture).ISA简单来说就是指令集体系结构.定义了处理机状态,指令格式以及指令对状态的影响.-机器级使用的存储器地址是虚拟地址. 机器代码中的处理机状态 程序计数器(PC)表示将要执行的下一条指令在存储器中的地址. 整数