应该使用字节缓冲区来签名还是使用unsigned char缓冲区?

jac*_*hab 54 c c++ buffer char

字节缓冲区应该是char或unsigned char还是char缓冲区?C和C++之间有什么区别?

谢谢.

Joh*_*itb 47

如果您打算存储任意二进制数据,则应使用unsigned char.它是唯一保证C标准没有填充位的数据类型.每个其他数据类型可以在其对象表示中包含填充位(即包含对象的所有位的填充位,而不是仅包含确定值的位).填充位的状态未指定,不用于存储值.因此,如果你使用char一些二进制数据读取,事情将被削减到char的值范围(通过仅解释值位),但可能仍然有一些位被忽略但仍然存在并被读取memcpy.很像真正的struct对象中的填充位.unsigned char保证类型不包含那些.接下来是5.2.4.2.1/2(C99 TC2,n1124):

如果在表达式中使用char类型的对象的值被视为有符号整数,则其值CHAR_MIN应与其值相同SCHAR_MIN且值的值CHAR_MAX应与.的值相同SCHAR_MAX.否则,值 CHAR_MIN应为0,其值CHAR_MAX应与.的值相同 UCHAR_MAX.价值UCHAR_MAX应相等2^CHAR_BIT ? 1

从最后一句话可以看出,任何填充位都没有空间.如果你使用char缓冲区的类型,你也有溢出的问题:明确地将任何值分配给8位数范围内的一个这样的元素- 所以你可能希望这样的赋值是正确的 - 但不在范围内a char,这是CHAR_MIN.. CHAR_MAX,这样的转换溢出并导致实现定义的结果,包括信号的提升.

即使对于上述可能不会在实际实施中出现任何问题(将是一个非常实行质量差),你是最好的,从开始之初,这是使用权类型unsigned char.

但是,对于字符串,选择的数据类型是char字符串和打印函数可以理解的.使用signed char这些目的看起来像一个错误的决定对我来说.

有关更多信息,请阅读this proposal其中包含下一版C标准的修复程序,最终将不需要signed char任何填充位.它已经纳入工作文件中.

  • 忘记C.` [C++ 11:3.9.1/1]:`[..] _一个char,一个有符号的char,一个unsigned char占用相同的存储空间并具有相同的对齐要求(3.11); 也就是说,它们具有相同的对象表示.对于字符类型,对象表示的所有位都参与值表示._ [..]这是否表明_all three_字符类型至少具有_same_填充?我进一步解释它意味着他们都没有. (7认同)
  • B-但是 C99 6.2.6.2 说“signed char 不应有任何填充位” (2认同)

dan*_*n04 33

字节缓冲区应该是char或unsigned char还是char缓冲区?C和C++之间有什么区别?

语言如何处理它的细微差别.一个巨大的如何约定的区别对待它.

  • char= ASCII(或UTF-8,但签名在那里的方式)文本数据
  • unsigned char =字节
  • signed char =很少使用

并且有代码依赖于这种区别.就在一两个星期前,我遇到了一个错误,其中JPEG数据被破坏,因为它被传递到char*我们的Base64编码功能的版本 - 它"帮助"替换了"字符串"中所有无效的UTF-8.改为BYTEaka unsigned char只是修复它所需要的.

  • 那么为什么C++ iostream使用`char*`而不是`unsigned char*`来表示通过`read`和`write`方法读写二进制流时的数据缓冲区?:P (7认同)
  • wtf java与此有关(呃) (4认同)
  • @developerbmw:Gosling 先生 [Java 的发明者] 看到了未提升为有符号整数类型的无符号类型所带来的所有困难,因此决定 Java 不应该有*任何* 无符号类型(除了——出于某种原因--`char`),而不是说——像 Pascal 这样的其他一些语言所做的那样——唯一的无符号类型应该是那些可以提升为有符号整数类型的类型。 (2认同)

RBe*_*eig 12

这取决于.

如果缓冲区旨在保存文本,那么将它声明为一个数组可能是有意义的char,让平台在默认情况下决定是签名还是无符号.例如,这将使您在将数据传入和传出实现的运行时库时遇到的麻烦最少.

如果缓冲区旨在保存二进制数据,那么它取决于您打算如何使用它.例如,如果二进制数据实际上是一个打包的数据样本数组,这些数据样本是带符号的8位定点ADC测量值,那么signed char这将是最好的.

在大多数实际情况中,缓冲区只是一个缓冲区,并且您并不真正关心单个字节的类型,因为您在批量操作中填充了缓冲区,并且您将要将其传递给解析器来解释复杂的数据结构并做一些有用的事情.在这种情况下,以最简单的方式声明它.


Pet*_*ham 9

如果它实际上是一个8位字节的缓冲区,而不是机器默认语言环境中的字符串,那么我会使用uint8_t.并不是说有很多机器,其中char不是一个字节(或一个字节是八位字节),但是使''这是一个八位字节的缓冲区'而不是'这是一个字符串'的语句通常是有用的文档.

  • POSIX读/写采用void*缓冲区.期望char*的POSIX函数(例如open()的path参数)期望字符串,而不是字节缓冲区. (4认同)

Ric*_*den 5

您应该使用charunsigned char,但从不签名char.该标准在3.9/2中有以下内容

对于POD类型T的任何对象(基类子对象除外),无论对象是否保持类型T的有效值,组成对象的基础字节(1.7)都可以复制到char或unsigned数组中char.如果将char或unsigned char数组的内容复制回对象,则该对象随后应保持其原始值.