精华内容
下载资源
问答
  • cpu并无法判断数据是有符号数还是无符号数,两种运算都进行,在标志寄存器中储存进位值或溢出值...有符号数与无符号数的区别在有符号数最高位是符号位。 转载于:https://www.cnblogs.com/xuehongyang/p/5388356.html...

    cpu并无法判断数据是有符号数还是无符号数,两种运算都进行,在标志寄存器中储存进位值或溢出值,到底是有符号数还是无符号数根据你的逻辑。

    有符号数与无符号数的区别在有符号数最高位是符号位。

    转载于:https://www.cnblogs.com/xuehongyang/p/5388356.html

    展开全文
  • 符号数的第一位用来标识符号位,而无符号数只能表示正数。   区别:(以4位数表示)   有符号数0000 到0111(0到7) + 1000到1111(-8到-1) 在计算机中数是用补码来存储的,正数的补码和原码一样,负数的补码...

    有符号数的第一位用来标识符号位,而无符号数只能表示正数。

     

    区别:(以4位数表示)

     

    有符号数0000 到0111(0到7)   +    1000到1111(-8到-1)

    在计算机中数是用补码来存储的,正数的补码和原码一样,负数的补码等于符号位不变其他位取反再加1。当达到最大正数0111(7的补码),再加1时为1000(补码)。

    负数补码的绝对值是连符号位取反加1,然后看成无符号数,所以1000表示-8,1001表示-7。


    无符号数:0000到1111(0到15)


    展开全文
  • 1,整形:(默认有符号数) 在内存中存是其对应二进制补码 char(存在内存中是其ASCLL码) short(短整型) int(整形) long(长整形) 2,浮点型: float double long double(不是所有编译器都支持) 3,构造类型...

    数据类型

    1,整形:(默认有符号数)

    在内存中存的是其对应二进制补码

    char(存在内存中是其ASCLL码)

    short(短整型)

    int(整形)

    long(长整形)

    2,浮点型:

    float

    double

    long double(不是所有编译器都支持)

    3,构造类型(自定义类型)

    数组

    结构体(struct)

    枚举(enum)

    联合体(union)

    4,指针类型

    void*

    float*

    short*

    char*

    5,空类型

    void


    一.整型在内存的存储

    首先我们要知道

    整数在计算机中存的是它的补码

    原码——>反码——>补码

    三者的运算规则为

    原码按位取反(符号位不变)——>反码。

    反码+1——>补码。

    在32位计算机中首位是符号位
    表示正负不表示大小。

    首位为1表示负数,首位为0表示正数。

    eg(都是32位)

    10000000000000000000000000000001表示-1

    00000000000000000000000000000001表示1

    对于正整数规定,它的原码,反码,补码都相同可以直接用。

    对于负数计算机存的补码不等,要转成原码才可以直到其大小。

    eg:
    1 1 1 1 1…1 1(32位)(符号位1说明是负数)补码

    1 1 1 1 1…1 0(32位)(补码-1到反码)

    1 0 0 0 0…0 1(32位)(符号位不变其余位按位取反到原码)

    原码首位为1说明是负数,发现值数字-1。

    -----------------------------------------------------------------

    整形在内存中存储补码的原因:

    使用补码可以将符号位和数值域统一处理,原反补的转化运算过程相同,不用增添其他的计算原件。

    eg:
    计算10-1的值

    10的二进制位原码与反码,补码相同
    0 0 0 0 0 0… 1 0 1 0

    -1在内存中存储的二进制位为
    1 1 1 1 1 1… 1 1 1 1

    相加为补码与补码相加

    0 0 0 0 0 0…0 1 0 1 0
    1 1 1 1 1 1…1 1 1 1 1

    在这里插入图片描述
    观察i在内存中的储存方式

    #include<stdio.h>
    int main()
    {
    	int i = 1;
    	return 0;
    }
    

    在这里插入图片描述
    而1的16进制为
    00 00 00 01
    发现这里是“倒着存数据”

    整形存储方式有多种,常见的有

    大端字节序储存与小端字节序储存

    1.大端字节序储存:
    (把一个数据的低位字节内容存在高地址处)

    2.小端字节序储存:
    (把一个数据的低位字节内容存在低字节处)

    eg:

    设 int a变量的地址为:0x 12 34 56 78(四个字节)

    在这里插入图片描述

    在这里插入图片描述

    应用:
    1,判断机器的存储方式

    #include<stdio.h>
    int main()
    {
    	int i = 1;
    	char* p =(char*) &i;
    	if (*p == 1)
    	{
    		printf("该计算机是小端存储");
    	}
    	else
    	{
    		printf("该计算机是大端存储");
    	}
    	return 0;
    }
    

    这里i=1的16进制位为:
    0x 00 00 00 01(四个字节)

    char*的访问权限只有一个字节

    如果p为1,说明先储存的是二进制的低字节位,为小端字节序储存
    如果
    p为0,说明先储存的是二进制的高字节位,为大端字节序储存

    整形提升

    eg:

    #include<stdio.h>
    int main()
    {
    	char a = 3;
    	char b = 137;
    	char c = a + b;
    	printf("%d",c);
    	return 0;
    }
    

    在这里插入图片描述
    发现这里并不是我们想的140,

    这是因为char类型大小是一个字节,而一个整形是4个字节

    char—8个比特位,

    int—32个比特位,

    整型提升是按照符号位进行提升的符号位就是二进制位的首位

    +号操作符操作的是int型,所以char类型先补到32位

    a=0 0 0 0 0 0 1 1(补位,符号位为0)

    a=0000…0 1 1(32位)

    b= 1 1 1 1 1 1 1 1(补位)

    b=0 0 0 0 0 0 1 1 1 1 1 1 1(32位)

    a+b=0 0…1 0 0 0 0 0 1 0(32位)

    c=a+b(c是字符类型,只能存8位,所以会发生截断)

    c=1 0 0 0 0 0 1 0

    printf("%d")所以c还要进行整形提升

    c的符号位是1,所以补1到32位

    c整型提升后

    1 1 1 1 1 1…1 0 0 0 0 0 1 0(32位)(补码)
    1 1 1 1 1 1…1 0 0 0 0 0 0 1(32位)(补码)
    1 0 0 0 0 0…0 1 1 1 1 1 1 0(32位)(原码)

    符号位为1说明是负数
    翻译原码得-116

    有些数字如果是无符号位数,整形提升补零
    整型提升只发生在有二进制位且大小小于int的时候

    在这里插入图片描述
    发生了整型提升。

    当从int转换成比int大的类型时不会出现这种情况,不会截断

    有符号数与无符号数

    #include<stdio.h>
    int main()
    {
    	char a = -1;
    	unsigned char b = -1;
    	printf("a=%d b=%d",a,b);
    }
    

    输出结果:在这里插入图片描述

    a发生了截断又发生了整形提升不在赘述。

    b的类型是unsigned char,二进制位为
    1 1 1 1 1 1 1 1
    0 0 0 0 0 0 0 0…1 1 1 1 1 1 1 1(32位)=255
    无符号数整形提升补0

    有符号char:
    在这里插入图片描述
    范围为-128~127。

    当超过取值范围时

    在这里插入图片描述
    (无符号)char:
    最大值为:1 1 1 1 1 1 1 1=255
    最小值为:0
    超过范围时:
    255+1=0

    eg:

    #include<stdio.h>
    #include<string.h>
    int main()
    {
    	char arr[1000];
    	for (int i = 0; i < 1000; i++)
    	{
    		arr[i] = -1 - i;
    	}
    	printf("%d",strlen(arr));
    	return 0;
    }
    

    在这里插入图片描述
    strlen读取到0会停止
    127+128=255

    其他无符号整形类似


    二.浮点数在内存中的存储

    在讨论这个问题前先看一个经典题目

    #include<stdio.h>
    int main()
    {
    	int n = 9;
    	float* p = (float*)&n;
    	printf("%d\n",n);
    	printf("%f\n",*p);
    	*p = 9.0;
    	printf("%d\n",n);
    	printf("%f\n",*p);
    }
    

    输出结果:
    在这里插入图片描述
    当n是整形时,以浮点数打印和以整形打印的数字不同。当n是浮点型时,以整形打印的和以浮点数打印的数字不同。

    说明整形与浮点型的存储方式不同。

    浮点数的储存这里以10.5为例

    10的二进制有效位为1 0 1 0。

    0.5所在的二进制位的权重为2^-1

    综上10.5=1 0 1 0 . 1=(-1) ^ 0 * 1 . 0 1 0 1 * 2 ^ 3;

    规定:
    1,任意的二进制浮点数可以表示为:
    (-1)^ S * M
    2 ^ E
    *

    其中
    S是符号位,正浮点数为0;负浮点数为1。

    M为有效数字,范围为1~2。

    E为指位数。

    2,对于单精度浮点型float:

    S 占 1bit, E 占 8bit,M占23bit

    其中M一定为1.XXXXXX,所以1不存在内存中
    23bit全部存小数位。

    对于双精度浮点型double:

    S 占 1bit,E 占 11bit,M占52bit

    其中M一定为1.XXXXXX,所以1不存在内存中
    23bit全部存小数位。

    S _E _M放的顺序为
    在这里插入图片描述

    3,规定E是无符号数

    对于单精度float

    E=真实e+127;再化成二进制

    eg: 10.5=1 0 1 0 . 1=(-1) ^ 0 * 1 . 0 1 0 1 * 2 ^ 3

    E=e+127=3+127=130

    对于双精度double:

    E=真实e+1023;再化成二进制

    (注意特殊情况

    1,当E的二进制位为全0时

    E=e真实+127;

    e真实特别小,很接近0,这时规定有效数字

    M (1.XXXXXXXXXXX)不写小数点前的1,

    且规定E=1-127= -126

    用来表示这个数字很小

    —————————————————————

    2,当E的二进制位为1时(这里只讨论单精度)

    E=e真实+127=255

    e真实很大,这个数字是 ± 无穷

    这是如果M为全0,表示无穷大,正负看S。

    这里不再更深的研究。

    这时再来看例题

    #include<stdio.h>
    int main()
    {
    	int n = 9;
    	float* p = (float*)&n;
    	printf("%d\n",n);
    	printf("%f\n",*p);
    	*p = 9.0;
    	printf("%d\n",n);
    	printf("%f\n",*p);
    }
    

    9的二进制位为:
    0 0 0 0 0 0 0 0…1 0 0 1(32位)

    当以浮点型打印时二进制会被拆分

    在这里插入图片描述

    同理浮点数9.0
    9.0=(-1)^0 *1.001 * 2 ^3

    S=0 M=1.001 E=127+3=130

    在这里插入图片描述

    所以最后打印的结果为
    在这里插入图片描述

    展开全文
  • 汇编中有符号与无符号的区别

    千次阅读 2015-04-27 10:17:49
    在汇编语言层面,声明变量时候,没有 signed 和 unsignde 之分,汇编器统统,将你输入整数字面量当作有符号数处理成补码存入到计算机中,只有这一个标准!汇编器不会区分有符号还是无符号然后用两个标准来处理...

    一、只有一个标准!


    在汇编语言层面,声明变量的时候,没有 signed   和   unsignde 之分,汇编器统统,将你输入的整数字面量当作有符号数处理成补码存入到计算机中,只有这一个标准!汇编器不会区分有符号还是无符号然后用两个标准来处理,它统统当作有符号的!并且统统汇编成补码!也就是说,db -20 汇编后为:EC ,而 db 236 汇编后也为 EC 。这里有一个小问题,思考深入的朋友会发现,db 是分配一个字节,那么一个字节能表示的有符号整数范围是:-128 ~ +127 ,那么 db 236 超过了这一范围,怎么可以?是的,+236 的补码的确超出了一个字节的表示范围,那么拿两个字节(当然更多的字节更好了)是可以装下的,应为:00 EC,也就是说 +236的补码应该是00 EC,一个字节装不下,但是,别忘了“截断”这个概念,就是说最后的结果被截断了,00 EC 是两个字节,被截断成 EC ,所以,这是个“美丽的错误”,为什么这么说?因为,当你把 236 当作无符号数时,它汇编后的结果正好也是 EC ,这下皆大欢喜了,虽然汇编器只用一个标准来处理,但是借用了“截断”这个美丽的错误后,得到的结果是符合两个标准的!也就是说,给你一个字节,你想输入有符号的数,比如 -20 那么汇编后的结果是正确的;如果你输入 236 那么你肯定当作无符号数来处理了(因为236不在一个字节能表示的有符号数的范围内啊),得到的结果也是正确的。于是给大家一个错觉:汇编器有两套标准,会区分有符号和无符号,然后分别汇编。其实,你们被骗了。:-)

    二、存在两套指令!

    第一点说明汇编器只用一个方法把整数字面量汇编成真正的机器数。但并不是说计算机不区分有符号数和无符号数,相反,计算机对有符号和无符号数区分的十分清晰,因为计算机进行某些同样功能的处理时有两套指令作为后备,这就是分别为有符号和无符号数准备的。但是,这里要强调一点,一个数到底是有符号数还是无符号数,计算机并不知道,这是由你来决定的,当你认为你要处理的数是有符号的,那么你就用那一套处理有符号数的指令,当你认为你要处理的数是无符号的,那就用处理无符号数的那一套指令。加减法只有一套指令,因为这一套指令同时适用于有符号和无符号。下面这些指令:mul div movzx … 是处理无符号数的,而这些:imul idiv movsx … 是处理有符号的。
    举例来说:
    内存里有 一个字节x 为:0x EC ,一个字节 y 为:0x 02 。当把x,y当作有符号数来看时,x = -20 ,y = +2 。当作无符号数看时,x = 236 ,y = 2 。下面进行加运算,用 add 指令,得到的结果为:0x EE ,那么这个 0x EE 当作有符号数就是:-18 ,无符号数就是 238 。所以,add 一个指令可以适用有符号和无符号两种情况。(呵呵,其实为什么要补码啊,就是为了这个呗,:-))
    乘法运算就不行了,必须用两套指令,有符号的情况下用imul 得到的结果是:0x FF D8 就是 -40 。无符号的情况下用 mul ,得到:0x 01 D8 就是 472 。(参看文后附录2例程)

    三、可爱又可怕的c语言。

    为什么又扯到 c 了?因为大多数遇到有符号还是无符号问题的朋友,都是c里面的 signed 和 unsigned 声明引起的,那为什么开头是从汇编讲起呢?因为我们现在用的c编译器,无论gcc 也好,vc6 的cl 也好,都是将c语言代码编译成汇编语言代码,然后再用汇编器汇编成机器码的。搞清楚了汇编,就相当于从根本上明白了c,而且,用机器的思维去考虑问题,必须用汇编。(我一般遇到什么奇怪的c语言的问题都是把它编译成汇编来看。)

    C 是可爱的,因为c符合kiss 原则,对机器的抽象程度刚刚好,让我们即提高了思维层面(比汇编的机器层面人性化多了),又不至于离机器太远 (像c# ,java之类就太远了)。当初K&R 版的c就是高级一点的汇编……:-)

    C又是可怕的,因为它把机器层面的所有的东西都反应了出来,像这个有没有符号的问题就是一例(java就不存在这个问题,因为它被设计成所有的整数都是有符号的)。为了说明c的可怕特举一例:

    #include <stdio.h> 
    #include <string.h> 

    int main()
    {
    int x = 2; 
    char * str = "abcd"; 
    int y = (x - strlen(str) ) / 2;

    printf("%d\n",y);
    }

    结果应该是 -1 但是却得到:2147483647 。为什么?因为strlen的返回值,类型是size_t,也就是unsigned int ,与 int 混合计算时类型被自动转换了,结果自然出乎意料。。。
    观察编译后的代码,除法指令为 div ,意味无符号除法。
    解决办法就是强制转换,变成 int y = (int)(x - strlen(str) ) / 2; 强制向有符号方向转换(编译器默认正好相反),这样一来,除法指令编译成 idiv 了。我们知道,就是同样状态的两个内存单位,用有符号处理指令 imul ,idiv 等得到的结果,与用 无符号处理指令mul,div等得到的结果,是截然不同的!所以牵扯到有符号无符号计算的问题,特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换时,无论gcc还是cl都不提示!!!)


    为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是 signed 的。(完)



    附录
    1:IA-32 Intel Architecture Software Developer’s Manual》第2卷PDF文档表述为“sign-extended imm8”,这个sign-extended 是符号扩展的意思。说说符号扩展:当操作数进行长度扩展时,既要让操作数变长又不能改变原数值,所以就出现了符号扩展一说。比如 movsx ax, 0xEC   ,执行扩展后,ax的值为:0xFFEC,长度变长了,结果没变,都是 -20 。

    2:两套乘法指令结果例程

    ;; 程序存储为 x.s 
    ;;--start--------------------------------------------------------

    extern printf 
    global main 

    section .data
    str1: db "%x",0x0d,0x0a,0 
    n: db 0x02
    section .text 
    main: 
    xor eax,eax
    mov al, 0xec
    mul   byte [n]   ;有符号乘法指令为: imul

    push eax
    push str1
    call printf 

    add esp,byte 4 
    ret 

    展开全文
  • 一、首先需要明白数据类型有符号与无符号的概念最明显的区别就是二者表示的范围不同: 无符号数中,所有的位都用于直接表示该值的大小。有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小。...
  • //无符号数最高位不是符号位,而就是数的一部分,无符号数不可能是负数。 //%u——输出unsigned int类型-即表示输出一个无符号十进制整型数据 //% d——输出int类型 signed int a = -10; printf("%d\n", a);
  • 最明显的区别就是二者表示的范围不同: 无符号数中,所有的位都用于直接表示该值的大小。有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小。我们举一个字节的数值对比: 无符号数: 1111 1111...
  • 介绍乘法指令分为无符号数乘法指令和有符号数乘法指令两种,它们唯一的区别是相乘的两个操作数是有符号数据还是无符号数据。乘法指令的被乘数是隐含操作数,乘数需在指令中显式写出来。执行指令时,CPU会根据乘数是8...
  • 只说最精华的: ...3. 有符号型和无符号型变量的区别在于二进制首位是否作为符号位:有符号型,首位最为符号位,0表示正,1表示负; 无符号型,首位和其他位一样作为数字位。 4. C语言中,变量...
  • n位二进制有符号数据补码表示范围:[−2n−1,2n−1−1][-2^{n-1} ,2^{n-1}-1][−2n−1,2n−1−1]。 n位二进制无符号数据(正数)补码(三码相同)表示范围:[0,2n−1][0 ,2^{n}-1][0,2n−1]。 6.补码补码是...
  • 有符号数无符号数探讨  这个问题,要是简单理解,是很容易,不过要是考虑深了,还真有些东西呢。 下面我就把这个东西尽量扩展一点,深入一点和大家说说。   一、只有一个标准!   在汇编语言...
  • C语言的有符号与无符号,二进制整数的扩展与截断     前一节说了整数的表示方式,...有符号数无符号数的本质区别其实就是采用的编码不同,前者采用补码编码,后者采用无符号编码.   在C语言中,有符号数和无符号数
  • addi是加立即指令,支持溢出检测,具体表现为:遇到溢出时,溢出错误标志变为高电平,传送到控制器cu中,导致此时寄存器写使能信号regwr无效,最终结果为不将运算结果写入目的寄存器。 addiu是加立即指令,不...
  • 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0。 & 按位 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。 l 按位或 两个相应的二进制位中只要一个为1,该位的...
  • 有符号与无符号的概念最明显的区别就是二者表示的范围不同无符号数中,所有的位都用于直接表示该值的大小。有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小。我们举一个字节的数值对比:...
  • 位 字节 INT 有符号无符号

    千次阅读 2018-10-23 11:24:36
    位(bit): 位,又称比特位,英文是BIT。表示意义是一个位,也就是1或者0。 字节(byte): 字节,又称8位二进制,英文是byte。...有符号与无符号区别就是有符号通过首位定义来区分正数与负数。主要是...
  • 本文详细描述了数据移位的问题:包括逻辑移位和算术移位的区别有符号数无符号数移位的区别,不同编译器下的移植性问题所在,数据左移时候可能产生的bug等。总结了几条有用的经验,提供了可验证的源代码。可直接...
  • 有符号位与无符号位最明显的区别就是二者的表示范围不同。 (无符号数: 0 ----------------- 255 、有符号数: -128 --------- 0 ---------- 127 ) 原码: 最高位是符号位,0代表正数,1代表负数,非符号位为改...
  • 我是否正确地说有符号无符号整数之间的区别是:无符号可以保持较大的正值,而不是负值。无符号使用前导位作为值的一部分,而带符号版本使用最左侧位来标识数字是正数还是负数。有符号整数可以包含正数和负数。还有...
  • 本文所指的特殊符号是指...对于新手,注意等号=关系运算符==的区别。2.分号;分号用于语句末尾,表示禁止输出。如果一条命令的末尾分号,MATLAB会默认将语句的第一个返回值输出到命令行窗口。注意,某些命令没...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 240
精华内容 96
关键字:

有符号数与无符号数的区别