<stdint.h>标准整数类型头文件

同样的,本篇之所以会讲解这个头文件是因为我们的BIF(2.1.1)会使用到这个头文件。

至于2.1.1什么时候更新,这个因为最近电脑的故障问题,又要送去维修,所以这个如果现在能发布也算比较有幸了。

就很多人会说封装函数库很困难,实际上是因为大家没有比较深入的去学习C语言,而且封装函数库只是集成标准库,并没有涉及底层逻辑和具体应用之类的。


头文件介绍

<stdint.h>全程是Standard Integer Types Header ,即“标准整数类型头文件

主要作用:提供一系列标准化的整数类型定义,这些类型具有明确的大小和符号特性,从而确保代码在不同的平台和编译器之间都有一定的可移植性。

准确地反映了它的功能和用途。

Standard

表示这些类型是标准化的,符合C语言标准(如我们上次说的C99)

Integer Types

表示这些类型是整数类型,包括有符号整数和无符号整数

Header

表示这是一个头文件,用于在C语言程序中包含这些类型定义。

这时候你可能要问了,既然这个头文件支持C99,那我们那个代码为什么不用这个头文件呢。

这个是只能应用在支持C99标准的头文件上,我后面去看了一下调查了一下我们的Keil,它对C99的支持存在一定的限制,但是我们可以通过配置来部分启用C99特性。具体的操作方法我放在后面了,以确保我们的Keil5能支持这个头文件。


具体内容介绍

<stdint.h>的实质很简单,他就是利用宏定义使得这个定义可以应用于不同的开发平台上。

接下来我会把里面所有的整数类型给大家介绍一下,如果想要快速了解的就直接通过目录来粗看一眼就可以了。

1.精确宽度整数类型

这个类型具有明确的位宽,确保在任何支持C99的平台上都有相同的大小。

位宽(Bit Width):指一个数据类型或数据存储单元所占用的二进制位的数量。不同的整数类型都有不同的位宽。这个在我们后续写这个具体的整数类型的时候我会附加在上面。

有符号整数类型

  • int8_t:8 位有符号整数 -128 ~ 127

  • int16_t:16 位有符号整数 -32768 ~ 32767

  • int32_t:32 位有符号整数 -2147483648 ~ 2147483647

  • int64_t:64 位有符号整数 -9223372036854775808 ~ 9223372036854775807

无符号整数类型

  • uint8_t:8 位无符号整数 0 ~ 255

  • uint16_t:16 位无符号整数 0 ~ 65535

  • uint32_t:32 位无符号整数 0 ~ 4294967295

  • uint64_t:64 位无符号整数 0 ~ 18446744073709551615

2.最小宽度整数类型 

这些类型至少具有指定的宽度,但可能更宽,具体取决于平台。

它与精确宽度整数类型的区别在下面讲述。

 有符号整数类型

  • int_least8_t:至少 8 位的有符号整数 -128 ~ 127

  • int_least16_t:至少 16 位的有符号整数 -32768 ~ 32767

  • int_least32_t:至少 32 位的有符号整数 -2147483648 ~ 2147483647

  • int_least64_t:至少 64 位的有符号整数 -9223372036854775808 ~ 9223372036854775807

无符号整数类型 

  • uint_least8_t:至少 8 位的无符号整数 0 ~ 255

  • uint_least16_t:至少 16 位的无符号整数 0 ~ 65535

  • uint_least32_t:至少 32 位的无符号整数 0 ~ 4294967295

  • uint_least64_t:至少 64 位的无符号整数 0 ~ 18446744073709551615


 精确与最小宽度整数类型的区别

精确宽度:提供具有 固定位宽 的整数类型,确保在所有支持C99的平台这些类型的大小完全一致。这主要适用于 精确控制数据大小 的场景。如我们在硬件编程,网络协议等,数据大小必须严格符合规范。

最小宽度:提供至少具有指定最小位宽的整数类型,但实际大小可能大于指定的最小位宽,这些因平台而异。适用于需要保证数据类型至少有某种最小宽度,但对具体大小没有严格要求的场景。如通用编程,性能优化等。


3.最大宽度整数类型

这些类型用于表示最大可能的有符号和无符号整数

intmax_t: 最大可能的有符号整数 -9223372036854775808 ~ 9223372036854775807

uintmax_t:最大可能的无符号整数 0 ~ 18446744073709551615

4.最快整数类型

当前平台执行速度最快,但可能比指定的最小位宽更宽

有符号整数类型

  • int_fast8_t:最快的至少 8 位的有符号整数 -128 ~ 127

  • int_fast16_t:最快的至少 16 位的有符号整数 -32768 ~ 32767

  • int_fast32_t:最快的至少 32 位的有符号整数 -2147483648 ~ 2147483647

  • int_fast64_t:最快的至少 64 位的有符号整数 -9223372036854775808 ~ 9223372036854775807

无符号整数类型

  • uint_fast8_t:最快的至少 8 位的无符号整数  0 ~ 255

  • uint_fast16_t:最快的至少 16 位的无符号整数 0 ~ 65535

  • uint_fast32_t:最快的至少 32 位的无符号整数 0 ~ 4294967295

  • uint_fast64_t:最快的至少 64 位的无符号整数 0 ~ 18446744073709551615

5.指针宽度整数类型

这些类型与指针的宽度相同,用于确保指针和整数之间的安全转换

有符号整数类型

  • intptr_t:与指针宽度相同的有符号整数 

无符号整数类型 

  • uintptr_t:与指针宽度相同的无符号整数

6.整数类型的极限值

(宏定义),用于表示各种整数类型的极限值,这些宏确保代码在不同平台有相同的边界值

有符号整数的最小值

  • INT8_MINint8_t 的最小值 -128 

  • INT16_MINint16_t 的最小值 -32768

  • INT32_MINint32_t 的最小值 -2147483648

  • INT64_MINint64_t 的最小值 -9223372036854775808

  • INT_LEAST8_MINint_least8_t 的最小值 -128

  • INT_LEAST16_MINint_least16_t 的最小值 -32768

  • INT_LEAST32_MINint_least32_t 的最小值 -2147483648

  • INT_LEAST64_MINint_least64_t 的最小值 -9223372036854775808

  • INT_FAST8_MINint_fast8_t 的最小值 -128

  • INT_FAST16_MINint_fast16_t 的最小值 -32768

  • INT_FAST32_MINint_fast32_t 的最小值 -2147483648

  • INT_FAST64_MINint_fast64_t 的最小值 -9223372036854775808
  • INTPTR_MINintptr_t 的最小值 -2147483648 (32位)/ -9223372036854775808(64位)

  • INTMAX_MINintmax_t 的最小值 -9223372036854775808

有符号整数的最大值

  • INT8_MAXint8_t 的最大值 127

  • INT16_MAXint16_t 的最大值 32767

  • INT32_MAXint32_t 的最大值 2147483647

  • INT64_MAXint64_t 的最大值 9223372036854775807

  • INT_LEAST8_MAXint_least8_t 的最大值 127

  • INT_LEAST16_MAXint_least16_t 的最大值 32767

  • INT_LEAST32_MAXint_least32_t 的最大值 2147483647

  • INT_LEAST64_MAXint_least64_t 的最大值 9223372036854775807

  • INT_FAST8_MAXint_fast8_t 的最大值 127

  • INT_FAST16_MAXint_fast16_t 的最大值 32767

  • INT_FAST32_MAXint_fast32_t 的最大值 2147483647

  • INT_FAST64_MAXint_fast64_t 的最大值 9223372036854775807

  • INTPTR_MAXintptr_t 的最大值 2147483647(32位)/ 9223372036854775807(64位)

  • INTMAX_MAXintmax_t 的最大值 9223372036854775807

无符号整数的最大值

  • UINT8_MAXuint8_t 的最大值 255

  • UINT16_MAXuint16_t 的最大值 65535

  • UINT32_MAXuint32_t 的最大值 4294967295

  • UINT64_MAXuint64_t 的最大值 18446744073709551615

  • UINT_LEAST8_MAXuint_least8_t 的最大值 255

  • UINT_LEAST16_MAXuint_least16_t 的最大值 65535

  • UINT_LEAST32_MAXuint_least32_t 的最大值 4294967295

  • UINT_LEAST64_MAXuint_least64_t 的最大值 18446744073709551615

  • UINT_FAST8_MAXuint_fast8_t 的最大值 255

  • UINT_FAST16_MAXuint_fast16_t 的最大值 65535

  • UINT_FAST32_MAXuint_fast32_t 的最大值 4294967295

  • UINT_FAST64_MAXuint_fast64_t 的最大值 18446744073709551615

  • UINTPTR_MAXuintptr_t 的最大值 32:4294967295 / 64:18446744073709551615

  • UINTMAX_MAXuintmax_t 的最大值 18446744073709551615

7.整数常量宏

用于表示各种整数类型的常量,确保在不同平台上具有相同的大小和符号

作用就是确保整数常量具有正确的类型(转换常量类型)实现的

有符号整数常量

  • INT8_C:用于表示 int8_t 的常量

  • INT16_C:用于表示 int16_t 的常量

  • INT32_C:用于表示 int32_t 的常量

  • INT64_C:用于表示 int64_t 的常量

无符号整数常量

  • UINT8_C:用于表示 uint8_t 的常量

  • UINT16_C:用于表示 uint16_t 的常量

  • UINT32_C:用于表示 uint32_t 的常量

  • UINT64_C:用于表示 uint64_t 的常量

最大宽度整数常量

  • INTMAX_C:用于表示 intmax_t 的常量

  • UINTMAX_C:用于表示 uintmax_t 的常量

8.其他定义

SIZE_MAX

size_t 的最大值。size_t 是一种无符号整数类型,通常用于表示对象的大小

如我们在经常使用的size函数就是用来计算某一变量的长度的。

uint8_t char_number = size(arr);//arr是一个字符数组

 SIZE_MAX 定义了 size_t 类型能够表示的最大值

PIPDIFF_MIN 和 PTRDIFF_MAX

分别表示 ptrdiff_t 的最小值和最大值。

ptrdiff_t 是一种有符号整数类型,用于表示两个指针之间的差值。这两个宏定义了 ptrdiff_t 类型的取值范围。

 SIG_ATOMIC_MIN  和 SIG_ATOMIC_MAX

分别表示 sig_atomic_t 的最小值和最大值。sig_atomic_t 是一种整数类型,用于在信号处理函数中安全地进行操作。这两个宏定义了 sig_atomic_t 类型的取值范围。

大家上面可能不太清楚哪个叫那个啊

uint 无符号、int 有符号、max 最大值、min 最小值、pip 指针类型、fast 最快整数、least 最小宽度、max 最大宽度(_左侧)


再叙·前缘

现在的你已经了解了这个函数库的所有定义内容,我们再来重新认识一下这个<stdint.h>

<stdint.h>的实现是通过宏定义吗

是的,<stdint.h>中的许多内容都是通过宏定义来实现的,这些宏定义提供了一种标准化的方式来访问和使用这些值,确保代码的可移植性和一致性。

事实上,绝大多数的函数都是采用宏定义的方法来增加代码的可移植性

那么你可能会想到,我们在keil编程中对单片机进行编程的时候,如引脚定义,如ADC采样,如配置时钟、高低电平等等,实际上都是通过宏定义、直接调用该文件的地址,对地址进行处理实现的。(如我们在上一篇文章说过的——寄存器地址映射)

#define GPIOA_BASE_ADDR 0x40020000
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE_ADDR)

 我们发现这个地址文件是一个16进制的数字,我们通过上一章讲过的位操作实现间接控制。

同样的HAL库也是采用同样的策略

#define __HAL_RCC_GPIOA_CLK_ENABLE()  (RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN))
void HAL_GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

 也是通过我们手动配置结构体,进而通过内部寄存器存储的引脚配置信息进行“读取”和“识别”(结构体信息),然后进行操作(硬件寄存器)。

HAL库安全在它通过更高层次的封装和抽象,将复杂的底层细节隐藏起来,我们的BIF函数库也是如此。

这个时候聪明的朋友就会想到,我们的地址都是针对于我们当前类型文件的,如果更换了平台,使用场景不就使用不了了吗?

我们一起来看一下<stdint.h>处理头文件的内部实现细节。

#define INT8_MIN (-128)
#define INT8_MAX 127

#define INT16_MIN (-32768)
#define INT16_MAX 32767

#define INT32_MIN (-2147483648)
#define INT32_MAX 2147483647

#define INT64_MIN (-9223372036854775808LL)
#define INT64_MAX 9223372036854775807LL

#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 4294967295U
#define UINT64_MAX 18446744073709551615ULL

这里为大家列出的是整数类型的极限值宏定义方法。

我们在前面已经铺垫过了,我们这里的宏定义实际上都是象征着:符号属性、位宽(取决于平台)以及取值范围


这个头文件在我们进行ADC采样的时候尤为有用(maybe)

最近一个月真的很忙啊,还碰上了校赛,有种南村群童欺我老无力的无助感,有的时候真的很感慨。不过,马上就是五一啦,我们会在五一回来后更新一部分BIF函数库,最近真的没有这些精力了。

在临近结束之前,我们再来聊聊keil中的C99标准配置环节吧。


keil如何配置C99

我们的认知中,keil都是以C语言为标准进行编程的,而C语言的标准是国际通用的C99标准,那么为什么keil会出现不支持C99的情况呢?

实际上,keil的年龄十分大了,keil的一些编译器默认遵顼的是旧版C标准(如C89、C90),而不是C99.

那么这些标准有什么区别呢?C90标准要求变量必须在代码块的开头声明,C99允许在代码块的任意位置声明变量。(这个任意位置真的省去了我们很多的麻烦,在我还在ACM的时候深有体会)

keil C51 主要用于 8051系列的微控制器,基于旧版本C标准,所以不支持C99 ,而我们的keil MDK_ARM 用于ARM架构的编译器(如 armcc) 就支持C99,但需要正确配置。

但是keil只是基于微控制器的编译器,并非专业的C语言开发软件,仍有一些C99特性无法支持,如我们上文所出现的。

 如果你的keil里没有C99Mode这个选项,则在Masic Controls 里面输入 “--C99”即可。

你可能会疑惑这个 " --gnu "是干什么的

--gnu 是一个编译器选项,用于启用对GNU C扩展的支持。GNU C是GNU编译器(GCC)中对标准C语言的扩展,它提供了一些额外的功能和特性,虽然不完全符合标准C ,但在某些情况下可以大大提高你的代码灵活性和效率。

这其中有计算机最爱的嵌套函数(汉诺塔问题等)、变量声明在代码块中间复合字面量(直接构造结构体或者联合体)、指定初始器等等。

启用“--gnu"就会避免各种编译错误(有的时候这也是一种弊端,出问题很难排查)。当然,--gnu 启用后,你的代码将不再完全符合标准CC ,需要在其他标准C编译器中编译代码,最好禁用--gnu 或者调整你的代码。

我就知道你们会问如果我想同时输入C99 和 GNU 应该怎么写

--gnu --c99

后事有曰

最近颇有感悟,我发现这个比赛如果不是为了热爱,那便失去了意义。但是在现实生活中,我们都在追求极致的奖项,为升学做准备。我们难道就应该说是学习阻拦了我们发展爱好的脚步吗?当然不能,只能说,在生活和梦想的权衡之下,我们最终沉默在了生活之中。

我最终去了电源组,电源组拿好奖难,我可能是个M,就喜欢没苦硬吃,但是我还是很享受这个探索、挖掘、发现一个个不起眼的东西时候的兴奋、惊讶的感觉。

(哇塞,我们模电老师也是这么说的)

以前不懂装懂,过度的包装让自己看起来十分臃肿,现在坦然地接受自己,从0开始,重新筑基,反倒有了轻松、踏实的感觉。

所以,在学习每一章内容,我都会寻根问底,了解它的底层逻辑。

比起别人眼中那个亮丽的自己,其实那个寻求真理,不顾一切向前奔去的你更加动人美丽。

除了研究电路、代码,我还是一个社会行为分析大师pwp,没想到吧!

大家如果对这方面感兴趣,就去关注我的海尔默理论吧,能否搜到就看缘分了,哈哈哈。

最近要准备小说《门的界》,里面是海尔默理论最出彩的一个部分——时间论。

其中我假设了世界个另一个维持状态的原因——时间因子,感兴趣的可以去起点上一看。

那么今天就到这里了,祝大家学有所成,马到成功。

学研之路遥遥无期,但探求真理之路永远昂扬向上,充满光芒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值