关于有符号数、无符号数和数据类型的总结

一、

  CPU只会根据输入信号进行逻辑运算,在硬件级别是没有有符号无符号的概念,运算结束会根据运算前的信号和输出信号来设置一些标志位,是不是有符号由写程 序的人决定,标志位要看你把操作数当有符号还是无符号来选择,就像内存中的数据,你可以按照需要来解析,原始数据在那里,你要按什么数据格式来解析在于自 己的选择,所以玩汇编的要做到心里有数,加减法只有一套指令,因为这一套指令同时适用于有符号和无符号。下面这些指令: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 。

二、

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 ,意味无符号除法,即将-2看做无符号数了。
解决办法就是强制转换,变成 int y = (int)(x - strlen(str) ) / 2; 强制向有符号方向转换(编译器默认正好相反),这样一来,除法指令编译成 idiv 了。我们知道,就是同样状态的两个内存单位,用有符号处理指令 imul ,idiv 等得到的结果,与用无符号处理指令mul,div等得到的结果,是截然不同的!所以牵扯到有符号无符号计算的问题,特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换时,无论gcc还是cl都不提示!!!)
为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是 signed 的。

三、自动类型转化时的,短字节向长字节转化时,有符号数会符号扩展,无符号数会0扩展;长字节向短字节转化时,会自动截取高位,留下低位字节。特别在做算术运算时,比如乘除法,就可能涉及到有符号数自动转化为无符号数,从而采用不同的指令处理。

例如:下面的代码输出是什么,为什么?

void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
    这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是 ”>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式 计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

扩展一下,如果是这段代码呢?

 

void foo(void)
{
unsigned int a = 6;
int b = -20;
printf("%d\n",a+b);
(a+b > 6) ? puts("> 6") : puts("<= 6");
}

结果是输出:-14   >6   

 

为什么?我们要注意,在printf()中,a+b也是转换为unsigned int(0xF2)的,但是%d要求又是按照有符号数输出,所以0xf2当成有符号数输出了-14。

四。特别注意在有常数的算数表达式中,往往有隐含的数据类型转化,因为整数常量并没有明确的被指出其的数据类型,

整常数在不加特别说明时总是正值。如果需要的是负值,则负号“-”必须放置于常数表达式的前面。

每个常数依其值要给出一种类型。当整常数应用于一表达式时,或出现有负号时,常数类型自动执行相应的转换,十进制常数可等价于带符号的整型或长整型,这取决于所需的常数的尺寸。

八进制和十六进制常数可对应整型、无符号整型、长整型或无符号长整型,具体类型也取决于常数的大小。如果常数可用整型表示,则使用整型。如果常数值大于一 个整型所能表示的最大值,但又小于整型位数所能表示的最大数,则使用无符号整型。同理,如果一个常数比无符号整型所表示的值还大,则它为长整型。如果需 要,当然也可用无符号长整型。

但是,可以在一个常数后面加一个字母l或L强制其数据类型,则认为是长整型。如1 0 L、7 9 L、0 1 2 L、0 11 5 L、0 X A L、0 x 4 f L等。

L, U, LU,叫类型后缀,. 

 一般在程序中出现3种数据.我把它们叫,变量,常量,字面量.
变量,常量一般都已经规定了类型了的,所以后缀针对的是字面量.
由于语言默认,整数是int型.即字面量 12 是 int型的.
如果要表示 长整型的12 就得加后缀 12L,无符号的 12U,无符号长整型的12UL.
具体这些有什么用,你需要了解整数在内存中的存放形式...存放长度(位)...

 

时间: 2024-10-26 14:04:33

关于有符号数、无符号数和数据类型的总结的相关文章

无符号数的问题,当length为0时报错

问题描述 无符号数的问题,当length为0时报错 #include float sum(float *,unsigned); int main(int argc, char *argv[]) { float a[5]={1,2,3,4,5}; float t=sum(a,0); printf("t=%fn",t); return 0; } float sum(float a[],unsigned length) { int i; float sum=0; for(i=0;i<l

c语言-C语言无符号数正负问题

问题描述 C语言无符号数正负问题 假设我们在对有符号值使用二进制补码云端的32位机器上运行代码.对于有符号值使用的是算术右移,而对于无符号值使用的是逻辑右移.变量的声明和初始化如下:int x=foo();//arbitrary valueint y=bar();//arbitrary valueunsigned ux = x;unsigned uy = y;对于下面表达式,或者证明对于所有的x和y值,它都为真,或者给出使得它为假的x和y值.A. (x>=0)||((2*x)<0)正确答案是A

关于无符号数相乘和补码相乘的疑问

问题描述 关于无符号数相乘和补码相乘的疑问 深入理解计算机系统中大概提到: 32位无符号相乘和二进制补码乘的位级行为是一样的?也就是说 x*y==ux*uy x和y是有符号的 而ux和uy是无符号. 这个是怎么理解的. 解决方案 首先用4位来解释,32位太长,不好解释,四位有符号数的范围是-8~7,无符号数是0~15. 1. 让我们设想一下有符号数的-2 * -2,-2的补码是1110,在无符号数里是14,所以无符号数的乘法相当于14 * 14 二进制乘法 1110 *1110 -------

printf-程序求解:为什么i*-1中,不是先把-1转化为无符号数4294967295,然后再与i相乘?

问题描述 程序求解:为什么i*-1中,不是先把-1转化为无符号数4294967295,然后再与i相乘? 程序如下: #include < stdio.h > int main() { unsigned int i=3; printf("%u ",i*-1); return 0; } 程序的输出为4294967293,也就是-3对应的无符号值. 为什么i*-1中,不是先把-1转化为无符号数4294967295,然后再与i相乘? 解决方案 首先 i*-1,这么写是人难以理解的,

汇编语言-汇编无符号数运算溢出

问题描述 汇编无符号数运算溢出 ##原文: mov al,0f0H add al,78H add指令执行后:CF=1,OF=0.对于无符号运算,0F0H+78H 有进位,CF=1:对于有符号数运算,0F0+78H不发生溢出,0F=0 ##个人理解: 0F0H+78H = 168H = 360 (十进制) 有符号8位所能表示范围是 -128 ~ 127 360 > 127 所以会产生 OF 有符号溢出 OF = 1 无符号8位所能表示范围是 0 ~ 255 360 > 255 所以会产生 CF

java实现无符号数转换、字符串补齐、md5、uuid、随机数示例_java

复制代码 代码如下: package com.hongyuan.test; import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Random;import java.util.UUID; /* * 杂项(无符号数转换,字符串补齐,md5,uuid,随机数) */public class SundryTest {  //转成无符号数 public stat

有符号数怎么为转换无符号数

问题描述 比如我数据库里面有个有符号的数-256我怎么在页面上面显示为无符号数里面的公式是多少马上结贴速度在线等···急 解决方案 解决方案二:你的意思是去掉负号??JS取绝对值不得了?alert(Math.abs(-256)); 解决方案三:"-256".replace(/-/g,"");替换掉"-",行么.解决方案四:我看了下论坛这个东西好像是c的东西测试的时候在数据库里面有个一个number类型的字段可是不能为负数我在java以及ext里面

PHP的数据类型

1.php基本数据类型:整型(integer).浮点类型(float/double).布尔类型(boolean).字符串型(string) 2.php复合数据类型:数组 array.对象 object 3.php特殊数据类型:包括null.资源类型. 整型(integer) 整型可以表示一个整数,比如: $a=10;$b=20; php中的整型数据,可以用十进制.八进制.十六进制. 例如: $a=0123; //八进制数,以0开头 $a=0x1A; //十六进制数,以0x开头 例: <?php

Swift教程之基础数据类型详解_Swift

基础类型 虽然Swift是一个为开发iOS和OS X app设计的全新编程语言,但是Swift的很多特性还是跟C和Objective-C相似. Swift也提供了与C和Objective-C类似的基础数据类型,包括整形Int.浮点数Double和Float.布尔类型Bool以及字符串类型String.Swift还提供了两种更强大的基本集合数据类型,Array和Dictionary,更详细的内容可以参考:Collection Types. 跟C语言一样,Swift使用特定的名称来定义和使用变量.同