在标题为Warning generated due wrong strcmp parameter handling的问题之后,似乎存在一些关于标准实际上保证字符类型的值表示的问题。
这看起来不错,但标准是否保证(1)总是会产生 true ?
char unsigned * p1 = ...;
char * p2 = reinterpret_cast<char *> (p1);
*p1 == *p2; // (1)
答案 0 :(得分:17)
但 C ++ 11 标准版(N3337)以及即将推出的 C ++ 14 中没有这样的保证( N3797)。
char unsigned * p1 = ...;
char * p2 = reinterpret_cast<char *> (p1);
*p1 == *p2; // (1), not guaranteed to be true
注意:无论char
是签名还是无符号,都是具体实施的; [basic.fundamental]p1
。功能
标准保证每种字符都应该;
共享相同数量的存储空间,对齐要求以及有关位参与的保证,意味着将引用一种类型( unsigned char )的左值转换为另一种类型( char ),就实际演员而言是安全的。
3.9.1p1
基本类型[basic.fundamental]
实施定义
char
是否可以保留负值。可以明确声明字符signed
或unsigned
。
char,
一个signed char,
和unsigned char
占用相同数量的存储空间并具有相同的对齐要求(3.11);也就是说,它们具有相同的对象表示。对于字符类型,对象表示的所有位都参与值表示。对于无符号字符类型,值表示的所有可能位模式表示数字。这些要求不适用于其他类型。
3.9p4
类型[basic.types]
类型为
T
的对象的对象表示是由类型{{{}对象占用的 Nunsigned char
个对象的序列1}}T,
等于N
。对象的值表示是保存类型sizeof(T)
的值的位集。
如果我们将 unsigned char (UCHAR_MAX)的最大值分配给T
而*p1
已签名,{ {1}}无法代表此值。我们会溢出*p2
,它最有可能最终获得*p2
的价值。
注意:有符号整数溢出实际上是未定义的行为。功能
*p2
-1
的双方必须具有相同的类型才能比较它们,目前一方是*p1 = UCHAR_MAX;
*p1 == *p2; // (1)
而另一方是operator==
。
编译器将因此使用整数提升来查找可以表示两种类型的所有组合可能值的类型;在这种情况下,结果类型将是unsigned char
。
在整数提升之后,语句在语义上等同于char
,这当然是错误的。
答案 1 :(得分:14)
strcmp (buf1, reinterpret_cast<char const *> (buf2));
看起来很好,
是的。 strcmp
获取const char *
个参数,但在内部将它们转换为const unsigned char *
(如果需要),这样即使char
已签名,两个不同的字节在查看时也可以相等char
,在使用strcmp
查看时,他们仍会比较不同。
C99:
7.21字符串处理
<string.h>
7.21.1字符串函数约定
3对于本子条款中的所有函数,每个字符都应被解释为具有类型
unsigned char
(因此每个可能的对象表示都是有效的并且具有不同的值)。
那就是说,
但标准是否保证(1)始终会产生 true ?
char unsigned * p1 = ...; char * p2 = reinterpret_cast<char *> (p1); *p1 == *p2; // (1)
您所写的内容无法保证。
使用带有二进制补码表示的带符号char
,8位字节的常见实现。如果*p1
为UCHAR_MAX
,则*p2 == -1
和*p1 == *p2
将为false,因为促销int
会为其提供不同的值。
如果您的意思是(char) *p1 == *p2
或*p1 == (unsigned char) *p2
,那么这些仍然无法保证,因此您需要确保从char
数组复制到数组unsigned char
,您不包含此类转化。