理解C语言有符号数和无符号数
- 格式:doc
- 大小:58.50 KB
- 文档页数:7
c语言中整型数据的存储形式在C语言中,整型数据(Integer)在内存中的存储形式是固定长度的二进制数。
它们可以是带符号数或无符号数,以及不同的长度和大小。
先说一下带符号数。
带符号整型数据可以表示负值。
在C语言中,最常用的带符号整型数据类型是int(整型),它占用4个字节(32位),可以表示从-2147483648到2147483647的整数值。
在存储带符号整型数据时,使用的是“二进制补码”(Two's Complement)表示法。
这种表示法是如此普遍的原因是它符合自然的加减运算法则,同时可以在CPU中用简单的电路实现。
比如,如果要存储-5这个数,首先将它的绝对值转化成二进制:5的二进制是101,接着将所有位取反得到010,最后加1得到011,这就是-5以二进制补码形式的存储形式:11111111 1111 1011。
再说说无符号整型数据(Unsigned Integer)。
它只能表示正整数,但在同样大小的空间内可以存储更大的值。
在C语言中,最常用的无符号整型数据类型是unsigned(无符号整数),它占用4个字节(32位),可以表示从0到4294967295的正整数值。
在存储无符号整型数据时,直接使用二进制表示这个数即可。
比如,如果要存储123这个数,直接将它转化成二进制即可:0111 1011。
除了int和unsigned,还有short(短整型)和long(长整型)等整型数据类型。
它们分别占用2个字节和8个字节。
这些数据类型在不同的编译器中占用的字节数可能不同。
无论用哪种整型数据类型,在内存中存储一个整型数据需要使用一块固定长度的内存空间。
对于32位的int,就需要4个字节的内存空间。
每个字节(Byte)由8个比特(Bit)组成,因此int变量会占用32个比特的空间。
这32个比特的位序(Bit Order)在不同的编译器和计算机体系结构中可能不同。
在存储整型数据时,常常需要考虑大小端(Endianness)的问题。
C语⾔中的整型、实型(浮点型)、字符常量详解⼀、整型常量在C语⾔中整型常量分为⼋进制、⼗进制、⼗六进制整型常量三种形式下述中均可负数在前⾯加负号-,后缀l或‘L'表⽰长整型,‘u'或‘U表⽰⽆符号数⼗进制整型常量除表⽰整数0外,不以0开头。
如:35、-11、22U、44u、8899L、67896l、345345LU、23453lu⼋进制整型常量以0开头的数字串表⽰⼋进制数,只能出现0~7的数字。
如:045、-076、06745l、0177777u……⼗六进制整型常量以0X或0x开头的连续数字和字母序列,序列中只能有0-9、A-F和 a-f这些数字和字母,字母a、b、c、 d、e、f分别对应数字10、11、12、13、14、15,⼤⼩写均可。
如:0x10、0X255、0xd4ef、0X6a7bL……⼆、实型常量实型常量有两种表⽰形式:⼀种是⼗进制⼩数形式,另⼀种是指数形式。
⼗进制⼩数形式包含⼀个⼩数点的⼗进制数字串。
此类实型常量⼩数点前或后可以没有数字,但不能同时没有数字。
例如:3.1415、.67、55.0、13.、0.0、-2.0指数形式指数形式的格式由两部分组成:⼗进制⼩数形式或⼗进制整型常量部分和指数部分。
其中指数部分是在e或E(相当于数学中幂底数10)后跟整数阶码(即可带符号的整数指数)。
例如: 2e15 //表⽰数值2×10^15 0.73e+1 //表⽰数值0.73×10^1 55e-1 //表⽰数值55×10^-1这些是错误的: e12、0.27e、24e-1.1三、字符常量⽤单引号括起来的⼀个字符。
如: 'a'、'A'、'='、'+'、'?'都是合法。
转义字符1. 转义字符是⼀种特殊的字符常量。
转义字符以反斜线"\"开头,后跟⼀个或⼏个字符。
C语言中有符号数,与无符号数的辨析关于有符号数,无符号数,你可能听过两种不同的回答。
一种是教科书,它会告诉你:计算机用“补码”表示负数。
可是有关“补码”的概念一说就得一节课,这一些我们需要在第6章中用一章的篇幅讲2进制的一切。
再者,用“补码”表示负数,其实一种公式,公式的作用在于告诉你,想得问题的答案,应该如何计算。
却并没有告诉你为什么用这个公式就可以和答案?另一种是一些程序员告诉你的:用二进制数的最高位表示符号,最高位是0,表示正数,最高位是1,表示负数。
这种说法本身没错,可是如果没有下文,那么它就是错的。
至少它不能解释,为什么字符类型的-1用二进制表示是“1111 1111”(16进制为FF);而不是我们更能理解的“10000001”。
(为什么说后者更好理解呢?因为既然说最高位是1时表示负数,那10000001不是正好是-1吗?)。
让我们从头说起。
1、你自已决定是否需要有正负。
就像我们必须决定某个量使用整数还是实数,使用多大的范围数一样,我们必须自已决定某个量是否需要正负。
在计算机中,可以区分正负的类型,称为有符类型,无正负的类型(只有正值),称为无符类型。
数值类型分为整型或实型,其中整型又分为无符类型或有符类型,而实型则只有有符类型。
字符类型也分为有符和无符类型。
2、使用二制数中的最高位表示正负。
首先得知道最高位是哪一位?1个字节的类型,如字符类型,最高位是第7位,2个字节的数,最高位是第15位,4个字节的数,最高位是第31位。
不同长度的数值类型,其最高位也就不同,但总是最左边的那位(如下示意)。
字符类型固定是1个字节,所以最高位总是第7位。
(红色为最高位)单字节数:11111111双字节数:1111111111111111四字节数:11111111111111111111111111111111当我们指定一个数量是无符号类型时,那么其最高位的1或0,和其它位一样,用来表示该数的大小。
当我们指定一个数量是无符号类型时,此时,最高数称为“符号位”。
c语言中数字类型后缀
在C语言中,数字类型后缀用于标识常量的数据类型。
这些后
缀可以确保编译器正确地解释常量,并将其存储为所需的数据类型。
以下是C语言中常用的数字类型后缀:
1. 整数类型后缀:
没有后缀,默认为int类型。
U或u,表示无符号整数,如10U。
L或l,表示长整数,如10L。
UL、Ul、uL或ul,表示无符号长整数,如10UL。
2. 浮点数类型后缀:
没有后缀,默认为double类型。
F或f,表示float类型,如3.14F。
L或l,表示long double类型,如3.14L。
3. 复数类型后缀:
I或i,表示复数类型,如3.0 + 4.0i。
这些后缀可以帮助程序员明确指定常量的数据类型,避免在表
达式中发生类型转换错误。
例如,当需要表示一个无符号长整数时,可以使用UL后缀来确保编译器将其解释为无符号长整数类型。
在实
际编程中,正确使用数字类型后缀可以提高代码的可读性和可维护性,同时避免潜在的类型转换问题。
总之,在C语言中,数字类型后缀是一种重要的标识符,用于
明确指定常量的数据类型,有助于编写清晰、准确的代码。
希望以
上回答能够满足你的需求,如果还有其他问题,欢迎继续提问。
在深入探讨C语言中有符号和无符号数混合运算之前,我们先来了解一下C语言中有符号和无符号数的基本概念。
在C语言中,有符号数和无符号数都是整数类型。
有符号数可以表示正数、负数和0,而无符号数只能表示非负数和0。
在C语言中,分别用int、long、short等关键字来声明有符号数变量,而用unsigned关键字声明无符号数变量。
接下来,我们将深入探讨C语言中有符号和无符号数混合运算的问题。
在C语言中,当有符号数和无符号数进行混合运算时,会发生隐式类型转换。
具体来说,当有符号数和无符号数进行运算时,无符号数会自动转换为有符号数,然后进行运算。
这种隐式类型转换可能导致一些意想不到的问题,特别是在涉及位运算时。
在进行有符号和无符号数混合运算时,我们需要特别注意以下几个方面:1. 数据类型的转换有符号数和无符号数进行混合运算时,需要注意数据类型的转换。
由于无符号数会自动转换为有符号数,可能导致数据溢出的问题,从而影响计算结果的准确性。
2. 位运算的问题在进行位运算时,由于有符号数和无符号数的不同表示方式,可能会导致结果不如预期。
在对有符号数进行右移操作时,如果该数为负数,则在高位补1;而对无符号数进行右移操作时,在高位补0。
3. 结果的理解在进行有符号和无符号数混合运算时,需要理解运算结果的真实含义。
尤其是在涉及到负数和溢出的情况下,对结果的理解更加重要。
在实际编程中,为了避免有符号和无符号数混合运算带来的问题,我们可以采取以下几点建议:1. 明确运算类型在进行有符号和无符号数混合运算时,可以显式地将无符号数转换为有符号数,以避免隐式类型转换可能带来的问题。
2. 谨慎使用位运算在进行位运算时,需要特别小心处理有符号和无符号数的混合运算,尤其是对负数的处理方式。
3. 结果的验证在进行有符号和无符号数混合运算后,需要对结果进行验证,确保结果的准确性和正确性。
总结回顾:在C语言中,有符号和无符号数混合运算可能会带来意想不到的问题。
C语⾔⼁关键字signed和unsigned的使⽤与区别详解在C语⾔中,signed/unsigned⽤于修饰整数变量,signed表⽰有符号的,unsigned表⽰⽆符号的。
今天就带⼤家了解⼀下关键字signed和unsigned 。
1、signedsign的本意是“标记,做记号”,ed后缀有⼀种完成时的感觉,这⾥表⽰的是有符号的。
signed关键字是ISO/ANSI C90标准新增的,其常见于整数类型的符号规定处。
signed的作⽤是:声明有符号类型的整数类型。
其实说signed很常见也不见得,因为我们常⽤的int、short和long,以及long long,默认情况下都是signed有符号的所以相⽐起来unsigned的戏份可能⽐signed更多,signed在这⾥只是相当于刻意地去说明其后⾯的变量是有符号类型的signed int a; /* 通常这⾥带signed的变量定义都可以省略掉signed,因为signed本⾝就是默认的 */signed short int b;signed short c;signed long int d;signed long e;signed long long f;unsigned int g; /* 写上signed后,上⾯的定义似乎在刻意地⼤声说“上⾯这些变量应该是有符号的” */unsigned short h; /* 但⼀般unsigned的戏份还是⽐signed多,signed关键字和auto关键字的宿命类似 */有符号数在计算机中的的表⽰⽅法:在计算机内部,是⽤补码表⽰有符号数-正数的补码是其本⾝-负数的补码为负数的绝对值得各个位取反加1举个例⼦:8位整数 5的补码为:0000 01018位整数 -7的补码为:取绝对值|-7| = 7 --> ⼆进制为 0000 0111 --> 各个位取反 1111 1000 -->最后加1 -->1111 1001,所以-7在计算机中就表⽰为1111 1001。
C语⾔⽆符号和有符号的区别C语⾔定义⼀个int类型时,默认是有符号数,关键字signed常省略,如:int a;signed int a;signed a;这三句是⼀样的定义定义⽆符号数时,必须加关键字unsigned,如:unsigned int a ;unsigned a;⽆符号关键字unsigned,只适⽤于int short long char四种变量,浮点型数据只有有符号类型。
那么为什么float会没有⽆符号呢?C语⾔中,整型是采⽤⼆进制表⽰的,⽽浮点数却是按照整数部分,⼩数部分,指数部分存放的。
运算也是分开来运算的。
这样的做法,使得浮点数可以表⽰很⼤的范围,所以unsigned⽆法作⽤于float,定义⽆符号的浮点型会出错。
不够的话,可以⽤double,双精度。
以32位机为例,int 分为⽆符号 unsigned 和有符号 signed 两种类型,默认为signed。
⼆者的区别就是⽆符号类型能保存2倍于有符号类型的数据。
32位下,signed int 的表⽰范围为:-2147483648 ~ 2147483647 (最⾼位做符号位)。
unsigned int 的表⽰范围为:0 ~ 4294967295 (不保留符号位)。
我们都知道,两个不同的数据类型在进⾏混合使⽤时,会⾃动进⾏类型转换。
其转换原则就是:向着精度更⾼、长度更长的⽅向转换。
也就是我们平常见到的 char 转为 int ,int 转为 long,float 转为 double . etc.那么当涉及到unsigned 类型时,⼜会进⾏怎样转换呢?ANSI C 标准采⽤值保留(value preserving)原则,就是当把⼏个整型操作数混合使⽤时,其结果的类型可能是有符号数,也可能是⽆符号数,这取决于操作数的类型的相对⼤⼩。
(通俗点说,就是两个整型数,如果都转换为signed不会丢失信息,就转换为signed;否则就转换为unsigned。
1.计算机中的符号位数据类型的最高位用于标识数据的符号。
最高位为1,表明这个数为负数;最高位为0,表明这个数为整数。
例程:#include <stdio.h>int main(void){char c = -5;short s = 6;int i = -7;printf("%d\n", (c & 0x80) != 0);printf("%d\n", (s & 0x8000) != 0);printf("%d\n", (i & 0x80000000) != 0); return 0;}输出:11在计算机内部用补码表示有符号数。
正数的补码为正数本身;负数的补码为负数的绝对值各位取反后加1。
举例:(1)8位整数5的补码为:0000 0101(2)8位整数-7的补码为:1111 10017 → 111 → 0000 0111 → 1111 1000 → 1111 1001 (3)16位整数20的补码为:0000 0000 0001 0100(4)16位整数-13的补码为:1111 1111 1111 001113 → 0000 0000 0000 1101 → 1111 1111 1111 0010 → 1111 1111 1111 0011在计算机内部用原码表示无符号数。
无符号数默认为正数;无符号数没有符号位。
对于固定长度的无符号数:MAX_VALUE + 1 → MIN_VALUEMIN_VALUE - 1 → MAX_VALUE4.signed和unsignedC语言中变量默认为有符号的类型。
unsigned关键字声明变量为无符号型。
C语言中只有整形数据能够声明unsigned变量。
#include <stdio.h>int main(void){unsigned int i = 5;int j = -10;if( ( i + j ) > 0 )printf("i + j > 0\n");elseprintf(" i + j <= 0\n");printf("i + j = %u\n", i + j );return 0;}输出:i + j > 0i + j = 4294967291#include <stdio.h>int main(void){unsigned int i = 0;for( i = 9; i >= 0; i-- ) printf("i = %u\n", i);return 0;}输出:不停输出较大数(1)有符号数用补码表示。
在C语言中,有符号数和无符号数的运算是一个非常基础但又容易引起混淆的概念。
在本文中,我将从简单的概念出发,逐步深入探讨有符号数和无符号数在C语言中的运算规则,并共享我的个人观点和理解。
1. 有符号数和无符号数的基本概念“有符号数”和“无符号数”是C语言中用来描述数据类型的两个重要概念。
有符号数是指可以表示正数、负数和零的数据类型,而无符号数则是只能表示非负数和零的数据类型。
在C语言中,int和char 等类型通常是有符号数,而unsigned int和unsigned char等类型则是无符号数。
2. 有符号数和无符号数之间的转换在C语言中,有符号数和无符号数之间可以相互转换。
当将一个无符号数赋值给一个有符号数时,编译器会按照规定进行符号扩展,即将无符号数的最高位作为符号位进行处理。
而将一个有符号数赋值给一个无符号数时,编译器会进行零扩展,即保持二进制位不变,但改变其解释方式。
3. 有符号数和无符号数的运算规则有符号数和无符号数在进行运算时遵循不同的规则。
在C语言中,如果一个有符号数和一个无符号数进行运算,那么有符号数会被隐式地转换为无符号数,然后再进行运算。
这意味着如果有符号数被转换为无符号数后变成了负数,那么会产生不可预期的结果。
在进行有符号数和无符号数的运算时,需要格外小心,避免出现意外的结果。
4. 个人观点和理解在我看来,有符号数和无符号数的运算是C语言中一个容易引起错误的地方。
在实际编程中,需要格外注意避免将有符号数和无符号数混合使用,以免造成不可预期的后果。
在进行有符号数和无符号数的运算时,建议尽量将它们转换为同一种类型再进行运算,以确保结果的准确性。
总结回顾本文首先介绍了有符号数和无符号数的基本概念,然后探讨了它们之间的转换规则和在运算中的注意事项,并共享了个人的观点和理解。
在日常编程中,我们需要格外小心有符号数和无符号数的运算,以免出现意外的结果。
在在C语言中,有符号数和无符号数的运算是一个需要格外小心的地方。
声明网上看到的文章,原文找不到了,原文被转载的不成样子,重复很多,整理花了很长时间,在翻看了维基百科后发现,原文中对于负数原码和补码存在一些问题,修改了一部分,原作者看到后可以联系我。
1、你自已决定是否需要有正负。
就像我们必须决定某个量使用整数还是实数,使用多大的范围数一样,我们必须自已决定某个量是否需要正负。
如果这个量不会有负值,那么我们可以定它为带正负的类型。
在计算机中,可以区分正负的类型,称为有符类型(signed),无正负的类型(只有正值),称为无符类型。
(unsigned)数值类型分为整型或实型,其中整型又分为无符类型或有符类型,而实型则只有符类型。
字符类型也分为有符和无符类型。
比如有两个量,年龄和库存,我们可以定前者为无符的字符类型,后者定为有符的整数类型。
2、使用二制数中的最高位表示正负。
首先得知道最高位是哪一位?1个字节的类型,如字符类型,最高位是第7位,2个字节的数,最高位是第15位,4个字节的数,最高位是第31位。
不同长度的数值类型,其最高位也就不同,但总是最左边的那位(如下示意)。
字符类型固定是1个字节,所以最高位总是第7位。
(红色为最高位)单字节数:11111111双字节数: 11111111 11111111四字节数:11111111 11111111 11111111 11111111当我们指定一个数量是无符号类型时,那么其最高位的1或0,和其它位一样,用来表示该数的大小。
当我们指定一个数量是无符号类型时,此时,最高数称为“符号位”。
为1时,表示该数为负值,为0时表示为正值。
3、无符号数和有符号数的范围区别。
无符号数中,所有的位都用于直接表示该值的大小。
有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小。
我们举一个字节的数值对比:无符号数:11111111 值:2551* 27 + 1* 26 + 1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20有符号数:01111111 值:1271* 26 + 1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20同样是一个字节,无符号数的最大值是255,而有符号数的最大值是127。
原因是有符号数中的最高位被挪去表示符号了。
并且,我们知道,最高位的权值也是最高的(对于1字节数来说是2的7次方=128),所以仅仅少于一位,最大值一下子减半。
不过,有符号数的长处是它可以表示负数。
因此,虽然它的在最大值缩水了,却在负值的方向出现了伸展。
我们仍一个字节的数值对比:无符号数:0 ----------------- 255有符号数:-128 --------- 0 ---------- 127同样是一个字节,无符号的最小值是0 ,而有符号数的最小值是-128。
所以二者能表达的不同的数值的个数都一样是256个。
只不过前者表达的是0到255这256个数,后者表达的是-128到+127这256个数。
一个有符号的数据类型的最小值是如何计算出来的呢?有符号的数据类型的最大值的计算方法完全和无符号一样,只不过它少了一个最高位(见第3点)。
但在负值范围内,数值的计算方法不能直接使用1* 26 + 1* 25 的公式进行转换。
在计算机中,负数除为最高位为1以外,还采用补码形式进行表达。
所以在计算其值前,需要对补码进行还原。
这里,先直观地看一眼补码的形式:在10进制中:1 表示正1,而加上负号:-1 表示和1相对的负值。
那么,我们会很容易认为在2进制中(1个字节):0000 0001 表示正1,则高位为1后:1000 0001应该表示-1。
然而,事实上计算机中的规定有些相反,请看下表:二进制值(1字节)十进制值10000000-12810000001 -12710000010-12610000011 -125…………11111110-211111111-1首先我们看到,从-1到-128,其二进制的最高位都是1,正如我们前面的学。
负数最高为为1然后我们有些奇怪地发现,1000 0000 并没有拿来表示-0;而1000 0001也不是拿来直观地表示-1。
事实上,-1 用1111 1111来表示。
怎么理解这个问题呢?先得问一句是-1大还是-128大?当然是-1 大。
-1是最大的负整数。
以此对应,计算机中无论是字符类型,或者是整数类型,也无论这个整数是几个字节。
它都用全1来表示-1。
比如一个字节的数值中:1111 1111表示-1,那么,1111 1111 - 1 是什么呢?和现实中的计算结果完全一致。
1111 1111 - 1 = 1111 1110,而1111 1110就是-2。
这样一直减下去,当减到只剩最高位用于表示符号的1以外,其它低位全为0时,就是最小的负值了,在一字节中,最小的负值是1000 0000,也就是-128。
我们以-1为例,来看看不同字节数的整数中,如何表达-1这个数:字节数二进制值十进制值单字节数11111111 -1双字节数 11111111 11111111 -1四字节数11111111 11111111 11111111 11111111 -1可能有同学这时会混了:为什么1111 1111 有时表示255,有时又表示-1?所以我再强调一下前面所说的第2点:你自已决定一个数是有符号还是无符号的。
写程序时,指定一个量是有符号的,那么当这个量的二进制各位上都是1时,它表示的数就是-1;相反,如果事选声明这个量是无符号的,此时它表示的就是该量允许的最大值,对于一个字节的数来说,最大值就是255。
我们已经知道计算机中,所有数据最终都是使用二进制数表达。
也已经学会如何将一个10进制数如何转换为二进制数。
不过,我们仍然没有学习一个负数如何用二进制表达。
比如,假设有一int 类型的数,值为5,那么,我们知道它在计算机中表示为:00000000 00000000 00000000 000001015转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。
现在想知道,-5在计算机中如何表示?在计算机中,负数以其正值的补码形式表达。
什么叫补码呢?这得从原码,反码说起。
原码:一个整数,按照绝对值大小转换成的二进制数,最高为为符号位,称为原码。
红色为符号位比如00000000 00000000 00000000 00000101 是5的原码。
10000000 00000000 00000000 00000101 是-5的原码反码:将二进制除符号位数按位取反,所得的新二进制数称为原二进制数的反码。
正数的反码为原码,负数的反码是原码符号位外按位取反。
取反操作指:原为1,得0;原为0,得1。
(1变0; 0变1)正数:正数的反码与原码相同。
负数:负数的反码,符号位为“1”,数值部分按位取反。
比如:将10000000 00000000 00000000 00000101除符号位每一位取反,得11111111 11111111 11111111 11111010。
称:11111111 11111111 11111111 11111010 是10000000 00000000 00000000 00000101 的反码。
反码是相互的,所以也可称:11111111 11111111 11111111 11111010 和10000000 00000000 00000000 00000101 互为反码。
补码:反码加1称为补码。
正数:正数的补码和原码相同。
负数:按照规则来也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。
11111111 11111111 11111111 11111010 是10000000 00000000 00000000 00000101(-5)的反码。
加1得11111111 11111111 11111111 11111011所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。
转换为十六进制:0xFFFFFFFB。
再举一例,我们来看整数-1在计算机中如何表示。
假设这也是一个int类型,那么:1、先取-1的原码: 10000000 00000000 00000000 000000012、除符号位取反得反码:11111111 11111111 11111111 111111103、加1得补码: 11111111 11111111 11111111 11111111可见,-1在计算机里用二进制表达就是全1。
16进制为:0xFFFFFF。
计算机中的带符号数用补码表示的优点:1、负数的补码与对应正数的补码之间的转换可以用同一种方法——求补运算完成,可以简化硬件;2、可将减法变为加法,省去减法器;3、无符号数及带符号数的加法运算可以用同一电路完成。
可得出一种心算求补的方法——从最低位开始至找到的第一个1均不变,符号位不变,这之间的各位“求反”(该方法仅用于做题)。
方法例1例21. 从右边开始,找到第一个'1' 10101001101011002. 反转从这个'1'之后开始到最左边(不包括符号位)的所有11010111 11010100 位。