C/C++为什么对二进制数据使用无符号字符?

是否真的需要像某些使用字符编码或二进制缓冲区的库中那样使用unsigned char来保存二进制数据?要理解我的问题,请看下面的代码-

char c[5], d[5];
c[0] = 0xF0;
c[1] = 0xA4;
c[2] = 0xAD;
c[3] = 0xA2;
c[4] = '';

printf("%s
", c);
memcpy(d, c, 5);
printf("%s
", d);

printf's??都正确输出,其中f0 a4 ad a2是Unicode码点U+24B62 (??)的十六进制编码。

Evenmemcpy也正确复制了字符保留的位。

什么理由可能主张使用unsigned char而不是plain char

在其他相关问题中突出显示unsigned char,因为它是C规范保证没有填充的唯一(字节/最小)数据类型。但如上面的例子所示,输出似乎不受任何填充的影响。

我已经用VC++Express 2010和MinGW编译了上面的代码。尽管VC给出了警告

warning C4309: '=' : truncation of constant value

输出似乎没有反映这一点。

附注:这可以标记为Should a buffer of bytes be signed or unsigned char buffer?的可能副本,但我的意图不同。我想问的是,为什么似乎可以与char一起工作的内容要键入unsigned char

更新:引用N3337,

Section 3.9 Types

对于平凡的任何对象(基类子对象除外) 可复制类型T,无论对象是否持有类型的有效值 T,则可以将组成对象的底层字节(1.7)复制到 字符或无符号字符的数组。如果字符数组的内容 或将无符号字符复制回对象中,则对象应 然后保持其原始值。

鉴于上述事实,而且我最初的示例是在char默认为signed char的Intel机器上,我仍然不确定是否应该优先使用unsigned char而不是char

还有别的事吗?


解决方案

在C中,unsigned char数据类型是唯一同时具有以下三个属性的数据类型

  • 它没有填充比特,所有存储比特都构成数据值
  • 从该类型的值开始的任何按位操作在转换回该类型时都不会产生溢出、陷阱表示或未定义的行为
  • 它可以在不违反"别名规则"的情况下为其他数据类型设置别名,即通过不同类型的指针访问同一数据将确保看到所有修改

如果这些是您要查找的"二进制"数据类型的属性,则您最终应该使用unsigned char

对于第二个属性,我们需要unsigned类型。对于这些,所有的转换都是用模算法定义的,在大多数99%的体系结构中,这里的模UCHAR_MAX+1256。因此,将较宽的值转换为unsigned char仅对应于截断到最低有效字节。

其他两种字符类型通常工作方式不同。无论如何,signed char是有符号的,所以不适合它的值的转换没有定义良好。char不固定为已签名或未签名,但在您的代码移植到的特定平台上,它可能已签名,即使它在您的平台上未签名。

相关文章