nig*_*ils 51 c c++ bytebuffer character-encoding rawbytestring
是否真的有必要unsigned char像在一些处理字符编码或二进制缓冲区的库中一样使用二进制数据?要理解我的问题,请看下面的代码 -
char c[5], d[5];
c[0] = 0xF0;
c[1] = 0xA4;
c[2] = 0xAD;
c[3] = 0xA2;
c[4] = '\0';
printf("%s\n", c);
memcpy(d, c, 5);
printf("%s\n", d);
Run Code Online (Sandbox Code Playgroud)
两者printf's输出 correctly, where f0 a4 ad a2Unicode代码点的编码U+24B62 ()在十六进制中.
甚至memcpy还正确地复制了char所持有的位.
什么推理可能主张使用unsigned char而不是plain char?
在其他相关问题unsigned char中突出显示,因为它是唯一的(字节/最小)数据类型,保证C规范没有填充.但正如上面的例子所示,输出似乎不受任何填充的影响.
我使用VC++ Express 2010和MinGW来编译上面的内容.虽然VC给出了警告
warning C4309: '=' : truncation of constant value
输出似乎没有反映出来.
PS这可以标记为可能重复的字节缓冲区应该是有符号的还是无符号的char缓冲区?但我的意图是不同的.我在问为什么一些似乎工作正常的东西char应该输入unsigned char?
更新:引用N3337,
Section 3.9 Types
2对于普通可复制类型T的任何对象(基类子对象除外),无论对象是否包含类型T的有效值,组成对象的基础字节(1.7)都可以复制到char数组中或unsigned char.如果将char或unsigned char数组的内容复制回对象,则该对象应随后保持其原始值.
鉴于上述事实,我的原始示例是在char默认情况下的英特尔机器上signed char,我仍然不相信是否unsigned char应该优先考虑char.
还要别的吗?
Jen*_*edt 84
在C中,unsigned char数据类型是唯一同时具有以下三个属性的数据类型
如果这些是您正在寻找的"二进制"数据类型的属性,那么您最终应该使用unsigned char.
对于第二个属性,我们需要一个类型unsigned.对于这些UCHAR_MAX+1,256在大多数99%的体系结构中,所有转换都使用模数arihmetic定义,此处为模数.所有较宽值的转换unsigned char因此仅对应于截断到最低有效字节.
另外两种字符类型通常不起作用.signed char无论如何,签名都是签名的,因此不适合转换不适合它的值.char不是固定为签名或未签名,但在您的代码移植到的特定平台上,即使它未经签名也可以签名.
Tom*_*ner 13
在比较单个字节的内容时,您将获得大部分问题:
char c[5];
c[0] = 0xff;
/*blah blah*/
if (c[0] == 0xff)
{
printf("good\n");
}
else
{
printf("bad\n");
}
Run Code Online (Sandbox Code Playgroud)
可以打印"坏",因为,根据你的编译器,c [0]将符号扩展为-1,这与0xff没有任何相同之处
Lun*_*din 12
普通char类型是有问题的,不应该用于除字符串之外的任何东西.主要问题char是您无法知道它是有符号还是无符号:这是实现定义的行为.这char与其他不同int,int总是保证签名.
虽然VC给出了警告......截断常数值
它告诉您,您正在尝试将int文字存储在char变量中.这可能与签名有关:如果您尝试在签名字符内存储值> 0x7F的整数,则可能会发生意外情况.形式上,这是C中的未定义行为,但实际上如果尝试将结果打印为存储在(带符号)char中的整数值,则只会得到一个奇怪的输出.
在这种特定情况下,警告无关紧要.
编辑:
在其他相关问题中,unsigned char被突出显示,因为它是唯一的(字节/最小)数据类型,保证C规范没有填充.
理论上,根据C11 6.2.6.2,除了unsigned char和signed char之外的所有整数类型都允许包含"填充位":
"对于unsigned char以外的无符号整数类型,对象表示的位应分为两组:值位和填充位(不需要任何后者)."
"对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位.不需要任何填充位; signed char不应有任何填充位."
C标准有意模糊和模糊,允许这些理论填充位,因为:
但是,在C标准之外的现实世界中,以下内容适用:
所以没有真正的理由使用unsigned char或signed char来躲避C标准中的一些理论场景.
字节通常用作无符号8位宽整数.
现在,char没有指定整数的符号:在某些编译器上,char可以被签名,而在其他编译器上它可能是未签名的.
如果我向你编写的代码添加一个位移操作,那么我将有一个未定义的行为.添加的比较也会产生意外结果.
char c[5], d[5];
c[0] = 0xF0;
c[1] = 0xA4;
c[2] = 0xAD;
c[3] = 0xA2;
c[4] = '\0';
c[0] >>= 1; // If char is signed, will the 7th bit go to 0 or stay the same?
bool isBiggerThan0 = c[0] > 0; // FALSE if char is signed!
printf("%s\n", c);
memcpy(d, c, 5);
printf("%s\n", d);
Run Code Online (Sandbox Code Playgroud)
关于编译期间的警告:如果char已签名,那么您正在尝试分配值0xf0,该值不能在signed char(范围-128到+127)中表示,因此它将被转换为有符号值( - 16).
将char声明为signed将删除警告,并且在没有任何警告的情况下进行干净构建总是很好.