例如,从 a 转换unsigned char *
为 a signed char *
(或只是 a char *
?
8 回答
The access is well-defined, you are allowed to access an object through a pointer to signed or unsigned type corresponding to the dynamic type of the object (3.10/15).
Additionally, signed char
is guaranteed not to have any trap values and as such you can safely read through the signed char
pointer no matter what the value of the original unsigned char
object was.
You can, of course, expect that the values you read through one pointer will be different from the values you read through the other one.
Edit: regarding sellibitze's comment, this is what 3.9.1/1 says.
A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (3.9); that is, they have the same object representation. For character types, all bits of the object representation participate in the value representation. For unsigned character types, all possible bit patterns of the value representation represent numbers.
So indeed it seems that signed char
may have trap values. Nice catch!
转换应该是安全的,因为您所做的只是从一种类型的字符转换为另一种类型的字符,它应该具有相同的大小。当您取消引用指针时,请注意您的代码期望的数据类型,因为两种数据类型的数值范围不同。(即,如果指针指向的数字最初是无符号的正数,则一旦将指针转换为有符号的 char* 并取消引用它,它可能会变成负数。)
强制转换会更改类型,但不会影响位表示。从 unsigned char 转换为 signed char 根本不会改变值,但会影响值的含义。
这是一个例子:
#include <stdio.h>
int main(int args, char** argv) {
/* example 1 */
unsigned char a_unsigned_char = 192;
signed char b_signed_char = b_unsigned_char;
printf("%d, %d\n", a_signed_char, a_unsigned_char); //192, -64
/* example 2 */
unsigned char b_unsigned_char = 32;
signed char a_signed_char = a_unsigned_char;
printf("%d, %d\n", b_signed_char, b_unsigned_char); //32, 32
return 0;
}
在第一个示例中,您有一个 unsigned char,其值为 192,或二进制 110000000。在转换为有符号字符之后,该值仍然是 110000000,但这恰好是 -64 的2s 补码表示。有符号值以 2s 补码表示形式存储。
In the second example, our unsigned initial value (32) is less than 128, so it seems unaffected by the cast. The binary representation is 00100000, which is still 32 in 2s-complement representation.
To "safely" cast from unsigned char to signed char, ensure the value is less than 128.
这取决于您将如何使用指针。您只是在转换指针类型。
您可以安全地将 an 转换unsigned char*
为 a char *
,因为您正在调用的函数将期待 char 指针的行为,但是,如果您的 char 值超过 127,那么您将得到一个与您预期不同的结果,所以请确保你在无符号数组中的内容对有符号数组有效。
我已经看到它在几个方面出错了,从无符号字符转换为有符号字符。
一,如果您将其用作数组的索引,则该索引可能会变为负数。
其次,如果输入到 switch 语句,它可能会导致负输入,这通常是 switch 不期望的。
第三,它在算术右移上有不同的行为
int x = ...;
char c = 128
unsigned char u = 128
c >> x;
有不同的结果
u >> x;
因为前者是符号扩展的,而后者不是。
第四,有符号字符在与无符号字符不同的点导致下溢。
所以一个常见的溢出检查,
(c + x > c)
可能会返回不同的结果
(u + x > u)
如果您只处理 ASCII 数据,则安全。
I'm astonished it hasn't been mentioned yet: Boost numeric cast should do the trick - but only for the data of course.
Pointers are always pointers. By casting them to a different type, you only change the way the compiler interprets the data pointed to.