【C 语言】数据类型的一致性

背景

今天使用Visual Studio 2017 写一个程序时发现的一个问题,做下记录。

目标实现

定义 char 类型的数组,将部分参数与宏进行比较,输出比较结果。

问题描述

问题代码

	char addbuf[8] = {0x5A, 0xA5, 0x00, 0x01};
	
	printf("-91's HEX: %x\r\n", -91);

	// 打印 addbuf
	for (int i = 0; i < 4; i++)
	{
		printf("addbuf[%d]'s HEX:%8x, DEC: %8d \r\n", i, addbuf[i], addbuf[i]);
	}

	if (addbuf[1] == 0xA5)
	{
		printf("Done\r\n");
	}
	else
	{
		printf("Undone\r\n");
	}

运行结果

在这里插入图片描述

分析

addbuf 数组的类型为 char,即其元素的表示范围为:
DEC:[ -128,127]
HEX:[0x00,0xFF]

对于 addbuf[1] 在初始化为 0xA5, 实际应用值为 -91。

  • 异常点 1:在对 addbuf 进行十六进制和十进制打印时,发现在 HEX 打印时,addbuf[1] 的值为 0xffffffa5。
  • 异常点 2:判断 addbuf[1] 是否等于 0xA5 时,判断结果为不等于,打印判断结果为:Undone。

首先,addbuf[1] 初始化为 0xA5。对于 0xA5 常量,系统会默认为是 int 类型的 165,而不是 char 类型的 -91。也就是说,在 addbuf[1] 初始化时,进行了一次强制类型转换。而对于此次的类型转换实际上是溢出的。

其次,%x 打印对象类型是 unsigned int。也就是说,所有的类型在进行打印之前,都会被强制转换为 unsigned int 类型再打印。所以,在对 addbuf[1] 进行 %x 打印时,出来的显示值为:0xffffffa5。

再儿,由于常量 0xA5 是 int 类型的 165,当拿 char 类型的 addbuf[1] 与 0xA5 比较时,相当于是 -91 与 165 进行比较,比较结果为:不相等。因此打印信息为:Undone。

解决方案

由分析可知,问题的根本原因是数据类型不一致导致的。只要将数据类型同一起来,就可以解决此问题。

方案 1

if 语句判断时,将 0xA5 强制转换类型为 char 类型。这不是个常规的方式,因为需要在每个比较运算的地方都需要加上强制类型转换,对于代码编写和维护,都不是个明智的选择。

	if (addbuf[1] == (char)0xA5)

方案 2

将 addbuf 定义为 unsigned char。此时能将数据类型统一为无符号类型,无论在比较或打印时,都不会出现异常了。

unsigned char addbuf[8] = { 0x5A, 0xA5, 0x00, 0x01 };

运行结果
在这里插入图片描述

方案 3

使用 #include "stdint.h"的数据类型。stdint.h 重新对整型进行了封装,从类型名称就可以得知数据的有效范围,对于不同的编译环境均能适用,更建议使用此方式。

typedef signed char        int8_t;
typedef short              int16_t;
typedef int                int32_t;
typedef long long          int64_t;
typedef unsigned char      uint8_t;
typedef unsigned short     uint16_t;
typedef unsigned int       uint32_t;
typedef unsigned long long uint64_t;

typedef signed char        int_least8_t;
typedef short              int_least16_t;
typedef int                int_least32_t;
typedef long long          int_least64_t;
typedef unsigned char      uint_least8_t;
typedef unsigned short     uint_least16_t;
typedef unsigned int       uint_least32_t;
typedef unsigned long long uint_least64_t;

typedef signed char        int_fast8_t;
typedef int                int_fast16_t;
typedef int                int_fast32_t;
typedef long long          int_fast64_t;
typedef unsigned char      uint_fast8_t;
typedef unsigned int       uint_fast16_t;
typedef unsigned int       uint_fast32_t;
typedef unsigned long long uint_fast64_t;

typedef long long          intmax_t;
typedef unsigned long long uintmax_t;

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/XiuHua_Wu/article/details/82843419
今日推荐