使用char还是unsigned char数组来存储原始数据更好?
在C++17之前,我们可以使用unsigned char
数组来存储原始数据。使用unsigned char
强调数据不仅仅是文本,如果我们从压缩流、数据库表备份文件、可执行映像或JPEG等地方获取到的是字节数据,那么unsigned
是适合具有二进制数据含义的。对于二进制数据,unsigned
在一些操作上更加合适,例如,对于一些位操作,对于有符号类型可能存在未定义行为和实现定义行为,并且unsigned
值可以直接用作数组的索引。此外,使用unsigned char*
传递给期望char*
的函数时,不会意外地将其操作为文本。在这些情况下,通常更自然地将值视为在0..255的范围内,毕竟,为什么"符号"位在数据中应该具有不同类型的意义呢?
另一方面,如果我们存储的是应用程序逻辑/设计层面上的8位数值数据,那么根据需要选择unsigned
或明确的signed
char
都可以。
需要注意的是,C++17引入了std::byte
,它更适用于存储"原始"数据缓冲区,而不是使用任何形式的char
。
总结起来,使用unsigned char
数组可以更清晰地表示数据不仅仅是文本,并且在处理二进制数据时更加方便和安全。对于存储的数据是8位数值的情况,可以根据需要选择unsigned
或signed
char
。在C++17及以后的版本中,可以考虑使用std::byte
来存储原始数据。
使用char
还是unsigned char
数组来存储原始数据,哪个更好?这个问题的出现是因为在操作这些值时存在一些差异。
在内部,它们完全相同:每个元素都是一个字节。区别在于当你操作这些值时。
如果你的值范围是[0,255],你应该使用unsigned char
,但如果是[-128,127],则应该使用signed char
。
假设你使用的是第一个范围(signed char
),那么你可以执行操作100+100
。否则,该操作将溢出并给出一个意外的值。
根据你的编译器或机器类型,默认情况下char
可能是无符号的或有符号的:
Is char signed or unsigned by default?
因此,char
具有上述情况的范围。
如果你只是用这个缓冲区来存储二进制数据而不对其进行操作,使用char
或unsigned char
没有区别。
编辑
请注意,你甚至可以使用编译器的标志更改默认的char
,即相同的机器和编译器:
-funsigned-char
让char类型成为无符号,就像unsigned char一样。
每种类型的机器都有一个默认值,用于指定char应该是像默认情况下的unsigned char一样还是像默认情况下的signed char一样。
理想情况下,一个可移植的程序应该总是在依赖对象的有符号性时使用signed char或unsigned char。但是,许多程序已经编写成使用plain char,并期望它被认为是有符号的,或者期望它被认为是无符号的,这取决于它们编写的机器。该选项及其相反选项允许你使这样的程序与相反的默认情况一起工作。
char类型始终是一个与signed char或unsigned char不同的类型,即使其行为总是像这两个类型之一。
你假设char
是有符号的。因此,“范围”和“溢出”这些部分不一定正确。
“如果是[-127,127]使用char
。”char
也可能是无符号的,如果你需要有符号性,请使用signed char
。“...会给你一个负数。”也许,也可能不是,有符号溢出是未定义行为。
这是正确的,但在这种情况下,用户不应该期望得到期望的值。
在存储原始数据时,使用char数组还是unsigned char数组哪种更好?这个问题的出现是因为以下几个原因:
首先,在缓冲区的结构上,两者没有什么区别:在两种情况下,你都得到一个被标准规定为一个字节的元素大小。
其次,最重要的区别是在访问缓冲区的单个元素时所看到的行为。使用char时,你会得到实现定义的有符号或无符号行为;而使用unsigned char时,你总是会看到无符号行为。这在你想要打印“原始数据”缓冲区的单个字节时非常重要。
另一个好的替代方案是使用精确宽度整数uint8_t作为缓冲区的类型。它保证具有与unsigned char相同的宽度,它的名称需要更少的输入,而且它告诉读者你不打算将缓冲区的单个元素用作字符信息。
因此,根据你的需求和预期的行为,你可以选择使用char数组、unsigned char数组或uint8_t作为存储原始数据的缓冲区类型。