C语言数据类型


前言

从小我们就接触和学习数学,我们现在能很清楚的说出常见的数有哪些种类,如整数、小数等,这两种数在我们的日常生活中使用的尤为频繁;C语言作为一个编程语言,其目的是更好地帮助我们完成日常的数据处理或者分析,因此C语言必然需要描述和体现生活中实际的数,这样才能更方便的进行数据的处理和计算。只不过C语言将这些数的类型进行了扩展,并最终称它们为 基本数据类型那C中的基本数据类型有哪些呢?本文章让我们一探究竟。

一、C的基本数据类型

C语言中基本数据类型有:整型、浮点型、字符型

通过下表,再联系我们说过C语言仅是帮助我们处理和分析数据的工具,我们可以比较直观的理解为什么C语言中会有这样活着那样的基本数据类型。

C语言中的基本数据类型(大类)实际的数的类型
整型整数
字符型
浮点型小数

值得一提的是,C语言定义字符型,是为了解决文本或者字符串等数据的,毕竟我们日常生活中,除了数字,还有很多的文本信息需要我们处理。

到这里我们仅仅介绍了C语言中为什么会有基本数据类型,但是我们知道一个数是有表示范围的,同时还会可能会有表示的精度,符号等信息,因此为了描述这些信息,C语言也需要对上面的基本数据类型进行细分,下面我们就进行进一步的介绍。

1.整型

整型分为:intshortlong,他们都能表示实际的整数

主要区别是:int、short和long修饰的变量,在内存中会占据的字节数是不相同的。

在C中int、short和long所占位数的如下:

类型Value
short至少16位,但不得超过int的位数
int至少16位,但不得超过long的位数,一般为16位或者32位
long至少32位,一般为32位或者64位

1.1 signed和unsigned限定符

我们从上面知道了不同的整型在内存中占据的位的长度,但实际计算时,这些还不够。

我们还需要知道:

  • 10进制与2进制之间如何转换,这需要提前知道这个数是signed还是unsigned的。
  • 更进一步还要知道原码、反码和补码(反码和补码是为了保证负数计算能获得正确结果)

Note:计算机中,所有整型数都以补码形式存储!!

我们通过下面一个例子介绍上面这些需要知道的要点,同时卖个关子,实际在计算机中所有整型的运算都是以补码形式进行的。

计算1+1=?并计算-1+1=?

实际通过C语言计算1+1或者-1+1就涉及到变量的声明了。

  • 当我们知道某个数一定是正数时,定义该变量为unsigned int类型
  • 如果这个数的符号不确定,或者带符号,则定义为signed int类型。

因此有:

unsigned int a = 1;
signed int b = -1;
signed int ans = 0;
ans = a + b;

为什么这么做,我先介绍完原码、反码和补码再说。

原码

首先我们需要将-1和1都表示成二进制形式,而在计算机中,用最高位的0和1分别表示8位二进制数的符号"+“号和”-"号。这就是十进制数的二进制原码形式
因此:

-1=1000 0001,1=0000 0001
所以:1+1=0000 0001+0000 0001=0000 0010=2,Bingo!
而-1+1=1000 0010=-2!很显然-1+1的结果不对。

这是因为,原码在计算含负数的运算时,会出错。

反码

正是因为原码计算负数会出错,因此前人创造了 反码。反码将8位二进制数的最高位视为符号位,对于正数和负数,反码的计算方式不同:

  • 正数原码=正数反码
  • 负数反码=负数对应的原码的符号位不变,其余为取反。

因此上面的1+1=?和-1+1=?会有下面的计算过程:

1 + 1 = 0000 0001 + 0000 0001 = 0000 0010 = 2(因为都是正数,正数反码=原码)
-1 + 1 = 1111 1110 + 0000 0001 = 1111 1111,此时结果是反码形式,因此转换成原码=1000 0000 = -0

这个-1+1在反码形式下计算结果好像还是有问题,因为-0应该就是0。

所以,计算机前辈又发明了补码

补码

对于正数和负数,各自的补码形式计算方式仍不相同:

正数补码 = 正数原码
负数原码 = 负数反码+1 = 负数原码符号位不变,其余为取反,再+1

因此,上面的1+1=?和-1+1=?计算过程如下:

1+1 = 0000 0001 + 0000 0001 = 0000 0010 = 2,因为正数补码=正数原码
-1+1 = 1111 1111 + 0000 0001 = 1 0000 0000,这里计算实际产生了溢出,如果是8位的char类型变量,结果就是 0000 0000 = 0。

这时结果终于正确了,下表做个关于原码、反码和补码的小总结。

原码反码补码
正数其二进制形式(辗转除)等于原码等于原码
负数符号位为1,其余位二进制形式原码符号位不变,其余位取反反码+1

不过还有一个问题,就是我们上面提到的unsigned和signed两个限定符,它的作用到底是什么呢?
我的理解是,就是限定的意思。它们既限定了变量的惟一的二进制补码形式,同时也限定了该变量所能容纳的数的范围。因为通过上面的原码、反码和补码我们知道了一个整数和负数在计算机中的存储形式,但是在没有限定符unsigned和signed的情况下,会造成错误。比如,129是一个正数,它在计算机中的补码 =原码 = 1000 0001,而-127作为一个负数,其在计算机中的存储形式为补码形式=1000 0001,129和-127的补码形式是相同的!这时候,仅通过这两个数的补码形式,是无法确定这个数到底是129还是-127,所需要以signed和unsigned来限定:

  • unsigned限定的char变量,其所有位都用于表示数值,没有符号位,因此unsigned限定char表示非负数,表示的范围为0~2^(16)-1= 0到255;那么unsigned int a的值的二进制如果是1000 0001时,a只能是129;
  • 而signed如果限定了char,则最高位用来表示符号,1为负,0为正;signed char类型变量所表示数的范围为-128~127。此时1000 0001就只能是-127了;

上面这个问题可能会在已知二进制补码情况下,反推10进制造成影响。因为通过补码,无法确定这个数到底是正数还是负数,所以补码反推出来的十进制结果应该是两种!

signed char表示范围问题(同signed int可表示-32768问题):

为什么signed char能表示-128?这与char所占的位相关,signed char除去符号位,比较好理解能表示-127 ~ 127,而-128实际的原码形式是:1 1000 0000,因此补码形式应该为 1 0111 1111 + 1 = 1 1000 000,而由于char只占8位,所以-128的补码形式是1000 0000,同时1000 0000仅对应了-128,所以可以用来表示-128这个数,这样-128~127恰好256个数。

给无符号char数赋值负数问题:

如果给无符号的char变量赋值负数,会进行转换;

unsigned char a = -42;
printf("%d\n", a);

// 结果是:213

上面的结果是计算机内部直接进行的,具体为:

该负数+8位2进制数的模值,所以转换过程为:-42+(2^8)=213

字符型

字符型包括:

  • unsigned char
  • signed char
  • char

字符型在上面的介绍中,稍微提了一嘴,char类型的变量在内存中恰好占据1B。

char类型变量,同样可用signed和unsigned修饰,分别表示-128~127范围内的数和[0,255]的数;除此之外,没有任何修饰的char也是单独的一种,不过没有unsigned和signed修饰的char型变量,其符号以及表示的范围由电脑和编译器决定。

unsigned charsigned charchar
表示数字范围0~255-128-127由计算机和编译器决定

如下面我用的WinGin编译运行的程序:

#include <stdio.h>
int main(){
	
	char a = 197;
	printf("%d\n", a);
	printf("%c\n", a);
	
	return 0;
}

结果为:

PS F:\C学习\C语言入门学习指南-习题> .\printf函数打印ASCII码.exe
-59

显然,这里的char默认是带符号的。

值得注意的是,根据上面的介绍,char型变量似乎和整型变量十分相似,这里确实是的,不过按照更加严谨的变量定义,char型变量就应该存储字符。

ASCII码和printf("%c", val)

ASCII码的定义不多做介绍,百度即可。不过我们要说的一个问题是如何打印字符——利用printf()的%c。

ASCII字符转换成数字形式的技巧:

char a;
while((c = getchar()) != EOF) {
	if (c >= '0' && c <= '9') {
		printf("%d", c - '0');
	}
	else{
		printf(c);
	}	
}

浮点型

浮点型就是小数,具体分 float、double、和long double。
浮点型的一些问题:

  • 不可比较大小;
  • 取余操作不可对浮点数计算
  • printf("%.3e", val)——可打印保留三位数的浮点数
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值