看到这个题目好多人肯定会迷惑,数据类型有什么可说的,这不是编程的基础吗?凡是会写代码的肯定都熟悉数据类型,不就是char,int,float,double这些每天都用成百上千次的的类型吗?各位看官切莫着急,且听我慢慢道来。
对于上位机开发来说,数据类型基本没有什么特别注意的,无非就是32位系统和64位系统的数据长度不一样。正是这个数据长度的问题,对于单片机开发来说,却是至关重要的。因为单片机有8位、16位、32位。如果不注意数据类型,不注意数据长度,那么在编写代码的时候,很容易就会造成数据溢出,导致程序出现bug,而且还很难发现原因。
如果熟悉stm32单片机开发的同学,看官方的例程时,使用的数据类型往往都是重新定义过的类型,很少有直接使用原始数据类型的,比如GPIOIO口设置。
这个变量的类型为uint16_t,查看这个数据类型的定义。
发现这个是给 unsigned short int 重新起了一个名字。好多人不明白,为什么官方都喜欢这样做,明明可以直接使用,为什么还要换个名字。
同样STM8单片机官方库里面使用的数据类型,也是重新起了一个名字。
这个uint16_t也是给 unsigned short 类型重新起了一个名字。
那么为什么要这样做吗?不嫌麻烦吗?自己平时写程序的时候,往往都是直接使用数据类型的默认名,也依然可以正常使用,没什么问题。但是官方为什么一定要重新定义一次数据类型呢?
这个说白了就是大局观的问题,因为官方比我们个人更具有大局观。个人面对的可能也只有几个平台和几款单片机。而官方面对的是多个平台和多种单片机的,这就不得不考虑数据兼容问题了。比如在32位单片机上的算法移植到8位单片机上,代码运行起来后,到处都是数据溢出。要挨个去修改变量的数据类型,那么这时候,作为开发者来说,奔溃不奔溃?抓狂不抓狂?
所以为了解决这个问题,官方就会在每个平台下,给数据类型,重新命名一次,如果需要更换平台,那么只需要替换这个数据重命名的头文件即可。
通过上面的对比可以看出,左边是32位单片机,右边是8位单片机。在32位单片机中int是32位,而在8位单片机中long 才是32位。那么在32位单片机上的int型变量,如果直接移植到8位单片机上的话,那么肯定就会出现数据溢出的问题。
那么如果使用了重命名后的新变量类型 uint32_t ,不论在8位和32位的单片机上,这个数据都会是32位,这样通过数据类型的重定义,就避免了,同样的数据类型,在不同平台上长度不一致的问题。
下面就实际检验一下不同平台上,不同类型的数据长度到底是多少。
8位单片机
通过sizeof函数计算出数据类型的位数,然后通过串口打印出来。
32单片机
同样通过sizeof函数计算出数据类型的位数,然后通过串口打印出来。
这里使用printf()函数打印的时候,使用%zd,来匹配sizeof()函数返回的数据类型,如果编译器不支持这个类型,可以使用%u或者%lu来代替。
接下来在电脑上,使用C++编译器,测试32位和64位系统中数据类型的长度。
Win32
将编译器设置为32位
输出结果为
win64
将编译器设置为64位
输出结果为:
不同平台数据类型所占字节对比
通过表格可以看出,8位和32位的系统的数据类型长度差别还是比较大的,在使用单片机开发的时候,要特别注意这一点。
如果在开发单片机的时候,不确定数据有没有超过范围,可以直接在数据类型声明的头文件中查看数据值的范围。
8位单片机数据值范围
32位单片机数据值范围
/* 7.18.2.1 */
/* minimum values of exact-width signed integer types */
#define INT8_MIN -128
#define INT16_MIN -32768
#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */
#define INT64_MIN __INT64_C(~0x7fffffffffffffff) /* -9223372036854775808 is unsigned */
/* maximum values of exact-width signed integer types */
#define INT8_MAX 127
#define INT16_MAX 32767
#define INT32_MAX 2147483647
#define INT64_MAX __INT64_C(9223372036854775807)
/* maximum values of exact-width unsigned integer types */
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 4294967295u
#define UINT64_MAX __UINT64_C(18446744073709551615)
/* 7.18.2.2 */
/* minimum values of minimum-width signed integer types */
#define INT_LEAST8_MIN -128
#define INT_LEAST16_MIN -32768
#define INT_LEAST32_MIN (~0x7fffffff)
#define INT_LEAST64_MIN __INT64_C(~0x7fffffffffffffff)
/* maximum values of minimum-width signed integer types */
#define INT_LEAST8_MAX 127
#define INT_LEAST16_MAX 32767
#define INT_LEAST32_MAX 2147483647
#define INT_LEAST64_MAX __INT64_C(9223372036854775807)
/* maximum values of minimum-width unsigned integer types */
#define UINT_LEAST8_MAX 255
#define UINT_LEAST16_MAX 65535
#define UINT_LEAST32_MAX 4294967295u
#define UINT_LEAST64_MAX __UINT64_C(18446744073709551615)
/* 7.18.2.3 */
/* minimum values of fastest minimum-width signed integer types */
#define INT_FAST8_MIN (~0x7fffffff)
#define INT_FAST16_MIN (~0x7fffffff)
#define INT_FAST32_MIN (~0x7fffffff)
#define INT_FAST64_MIN __INT64_C(~0x7fffffffffffffff)
/* maximum values of fastest minimum-width signed integer types */
#define INT_FAST8_MAX 2147483647
#define INT_FAST16_MAX 2147483647
#define INT_FAST32_MAX 2147483647
#define INT_FAST64_MAX __INT64_C(9223372036854775807)
/* maximum values of fastest minimum-width unsigned integer types */
#define UINT_FAST8_MAX 4294967295u
#define UINT_FAST16_MAX 4294967295u
#define UINT_FAST32_MAX 4294967295u
#define UINT_FAST64_MAX __UINT64_C(18446744073709551615)
/* 7.18.2.4 */
/* minimum value of pointer-holding signed integer type */
#if __sizeof_ptr == 8
#define INTPTR_MIN INT64_MIN
#else
#define INTPTR_MIN INT32_MIN
#endif
/* maximum value of pointer-holding signed integer type */
#if __sizeof_ptr == 8
#define INTPTR_MAX INT64_MAX
#else
#define INTPTR_MAX INT32_MAX
#endif
/* maximum value of pointer-holding unsigned integer type */
#if __sizeof_ptr == 8
#define UINTPTR_MAX UINT64_MAX
#else
#define UINTPTR_MAX UINT32_MAX
#endif
/* 7.18.2.5 */
/* minimum value of greatest-width signed integer type */
#define INTMAX_MIN __ESCAPE__(~0x7fffffffffffffffll)
/* maximum value of greatest-width signed integer type */
#define INTMAX_MAX __ESCAPE__(9223372036854775807ll)
/* maximum value of greatest-width unsigned integer type */
#define UINTMAX_MAX __ESCAPE__(18446744073709551615ull)
/* 7.18.3 */
/* limits of ptrdiff_t */
#if __sizeof_ptr == 8
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#else
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
#endif
/* limits of sig_atomic_t */
#define SIG_ATOMIC_MIN (~0x7fffffff)
#define SIG_ATOMIC_MAX 2147483647
/* limit of size_t */
#if __sizeof_ptr == 8
#define SIZE_MAX UINT64_MAX
#else
#define SIZE_MAX UINT32_MAX
#endif
/* limits of wchar_t */
/* NB we have to undef and redef because they're defined in both
* stdint.h and wchar.h */
#undef WCHAR_MIN
#undef WCHAR_MAX
#if defined(__WCHAR32) || (defined(__ARM_SIZEOF_WCHAR_T) && __ARM_SIZEOF_WCHAR_T == 4)
#define WCHAR_MIN 0
#define WCHAR_MAX 0xffffffffU
#else
#define WCHAR_MIN 0
#define WCHAR_MAX 65535
#endif
/* limits of wint_t */
#define WINT_MIN (~0x7fffffff)
#define WINT_MAX 2147483647
不同系统上的数据长度尽然会不一样,但是数据类型的具体范围没有规定吗?的确没有规定,C语言规范中只规定了每个数据类型的最小范围。
int — 系统给定的基本数据类型。 int类型不小于16位。
short 或者 short int — 最大的short 类型整数小于或者等于最大的int类型整数。short类型至少占16位。
long 或者 long int — 大于或等于最大的int类型整数。long型至少占32位。
long long 或者 long long int — 该类型可表示的整数大于或者等于最大的long类型整数。long long类型至少占64位。