嵌入式C语言学习记录(一)
C语言数据类型
C语言的基 本 数 据 类 型 由 11 个 关 键 字 组 成 : int 、 long 、 short 、unsigned、char、float、double、signed、_Bool、_Complex和_Imaginary。
short、int、long、long long
C标准对基本数据类型只规定了允许的最小大小,在不同位数的系统中可能有所不一样。本文的程序均是在32位系统(PC和STM32)中测试。
范围大小:shor t<= int <= long <= long long
默认有符号:int、short、long、long long
short:全称为short int, C语言规定了short占用的存储空间不能多于int,在不同位数的系统中所能表达的范围不一样。stm32中所能表示的最大范围是[-32768,32767]
int(4字节):取值范围为[-2147483648,2147483647]。[-232-1,232-1]
long:全称为long int,占用的存储空间可能比int多(可以表示的范围大于或大于[-32768,32767]),stm32中所能表示的最大范围是[-2147483648,2147483647](-232-1——232-1)
long long:全称为long long int, 占用的存储空间可能比long多,可以表示的范围大于或大于[-2147483648,2147483647],stm32中所能表示的最大范围是[-2147483648,2147483647](-232-1——232-1)
signed、unsigned修饰字符强调是否带符号
signed:强调是带符号类型,short、short int、signed short、signed short int都表示同一种类型。
unsigned:强调是无符号类型
不同数据类型的要使用对应的打印格式,否则会产生格式转换导致观察的数据有误
/测试代码如下/
#include <limits.h>//该头文件中定义了各个类型的取值范围
/*short类型
* 2byte(字节)= 16bit(位),表示范围,[-32768,32767]*/
printf("short:%d byte,[%d,%d]",sizeof(short),SHRT_MIN,SHRT_MAX);
/*int类型
* 4byte(字节)=32bit(位),表示范围[-2147483648,2147483647]*/
printf("int:%d byte,[%d,%d]\r\n",sizeof(int),INT_MIN,INT_MAX);
/*long int类型
* 4byte(字节)=32bit(位),表示范围[-2147483648,2147483647]*/
printf("long int:%d byte,[%ld,%ld]\r\n",sizeof(long int),LONG_MIN,LONG_MAX);
/*long long int类型
* 8byte(字节)=64bit(位),理论是应该是64位,
* 实际上由于STM32芯片限制最大值为32位
* 表示范围大小与long int类型相同,[-2147483648,2147483647]*/
printf("long long int:%d byte,[%lld,%lld]\r\n",sizeof(long long int),LLONG_MIN,LLONG_MAX);
/*unsigned short类型
* 2byte(字节)= 16bit(位),表示范围,[65535]*/
printf("unsigned short:%d byte,[%d,%d]",sizeof(short),0,USHRT_MAX);
/*unsigned int类型
* 4byte(字节)=32bit(位),表示范围[0,4294967295]*/
printf("unsigned int:%d byte,[%d,%u]\r\n",sizeof(unsigned int),0,UINT_MAX);
/*unsigned long int类型
* 4byte(字节)=32bit(位),表示范围[0,4294967295]*/
printf("unsigned int:%d byte,[%d,%lu]\r\n",sizeof(unsigned long int),0,ULONG_MAX);
/*unsigned long long int类型
* 8byte(字节)=64bit(位),理论是应该是64位,
* 实际上由于STM32芯片限制最大值为32位
* 表示范围大小与long int类型相同,[0,4,294,967,295]*/
printf("unsigned int:%d byte,[%d,%llu]\r\n",sizeof(unsigned long long int),0,ULLONG_MAX);
C语言只规定了以上几种数据类型,在stm32中常用到的uint8_t、uint16_t、uint32_t等都是基于上述类型利用typedef重定义构造成的。在库文件stdint.h中可以查到
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
char
char:该类型用于储存字符,但是从本质上看,char类型实际上是用特定的整数表示特定的字符。这也就是所谓的ASCLL编码。C语言把1字节定义为char类型占用的位(bit)数,因此无论是16位还是32位系统,都可以使用char类型。
取值范围:[-128,127]或者[0,255]。不同的编译器不一样,有些C编译器把char实现为有符号类型,则char可表示的范围是-128~127。而有些C编译器把char实现为无符号类型,那么char可表示的范围是0~255。可跳转到limits.h头文件查看定义的内容。(在CUBEIDE中有好几个不同路径的limits.h头文件,不方便跳转到真正定义的地方。在Keil5可以直接跳转到最底层的文件)
浮点类型——float、double
float:有效数据为6~7位
double:有效数据为15~16位
测试代码如下
#include<stdio.h>
void main()
{
float a = 1.0123456890;
double b = 1.01234567890123456789;
printf("a = %.10f,b = %.20f",a,b);
}
输出结果为:a = 1.0123456717,b = 1.01234567890123460000
由此处可以看出,当数据超过规定的小数位之后就会发生数据错误,如果想在程序中想要表示更高精度的数据可以采用定点数学的方式对数据进行处理。
浮点数在内存中的存储方式也和整数不一样。
- float: 1bit(符号位)+ 8bits(指数位) + 23bits(尾数位)
- double: 1bit(符号位)+11bits(指数位)+ 52bits(尾数位)
浮点数的转换步骤分为如下三步:
- 将浮点数转换成二进制
- 用科学计数法表示二进制浮点数
- 计算指数偏移后的值(float偏移量值为127,double偏移量值为1023)
实例:float型的浮点数8.25在内存中的转换和表示
- 先将8.25转换为二进制 -> 1000.01
- 将转换的二进制用科学计数法表示 -> 1.00001 * (2^3)
- 计算指数偏移后的值 -> 127 + 3 = 130 -> 100000010
经过以上三步,就可以得出:
- 符号位:0
- 指数:100000010
- 小数:00001
- 所以float型的8.25在内存中的表示为:0 100000010 00001 00000000000000000 (32位表示)
相比于整数,浮点数存入内存中花费了更多的步骤和时间,如果利用浮点数进行运算,花费的时间就需要更多了。
一个优秀的嵌入式工程师要尽量避免浮点运算!
布尔类型与其他类型
_Bool:C99新增关键字,布尔类型。布尔类型是无符号 int类型,所占用的空间只能储存0或1,用于表示逻辑值 true和false。必须设置C99标准才能实现(keil5默认是C89标准)。
_Complex和_Imaginary:分别是复数类型和虚数类型,在嵌入式中几乎不会运用到这种类型。
定义准确的数据类型对程序十分重要,合格的开发者应该选择准确的数据格式!