在带有 c 的 Linux 中,我不明白当我读/写二进制缓冲区时char*
和之间有什么区别?unsigned char*
什么时候不能用char*
,什么时候需要用unsigned char*
?
首先回忆 C 有unsigned char
,signed char
和char
: 3 种不同的类型。 与或char
具有相同的范围 。unsigned char
signed char
[编辑]
OP 添加了“当我读/写二进制缓冲区时”,因此下面的部分(我的原始帖子)处理“和之间有什么区别”,char*
并unsigned char*
带有一个没有该 r/w 问题的示例案例。在本节中......
可以使用任何 I/O 函数来读取/写入二进制文件,<stdio.h>
尽管使用fread()/fwite()
.
对于面向字节的数据,所有 I/O 函数的行为就像
字节输入函数从流中读取字符,就像通过连续调用
fgetc
函数一样。C17dr § 7.21.3 11
字节输出函数将字符写入流,就好像通过连续调用fputc
函数一样。§ 7.21.3 12
那么让我们看看这两个。
...
fgetc
函数将该字符作为unsigned char
... § 7.21.7.1 2
该fputc
函数写入 c 指定的字符(转换为 anunsigned char
) § 7.21.7.3 2
因此,最好将最低级别的所有 I/O 视为读/写unsigned char
。
现在直接解决
什么时候不能用
char*
,什么时候需要用unsigned char*
?(OP)
通过写入,可以在 OP 级代码中使用 诸如 或其他指针char*
,但底层输出函数通过. 这对 OP 的写入执行没有影响,除非被编码为一个的补码/符号幅度 - 不会检测到陷阱代码。unsigned char*
unsigned char *
char
与读取类似,底层输入函数通过保存数据unsigned char *
并且不会发生陷阱。即使是有符号的,通过读取的单个字节int fgetc()
也会报告该范围内的值。unsigned char
char
unsigned char*
在读/写二进制缓冲区中使用vs.的重要性char*
不在于 I/O 调用本身(全部unsigned char *
访问),而在于写入前的数据设置和读取后的数据解释 - 见memcmp()
下文。
什么时候不能用
char*
,什么时候需要用unsigned char*
?
一个很好的例子是与字符串相关的代码。
尽管函数参数中<string.h>
使用char*
了函数,但实现的执行就像char
是一样unsigned char
,即使char
是签名时也是如此。
对于本子条款中的所有函数,每个字符都应被解释为好像它具有类型
unsigned char
(因此每个可能的对象表示都是有效的并且具有不同的值)。C17dr § 7.24.1 3
因此,即使 ifchar
是有符号 char
的,函数也像int strcmp(char *a, char *b)
if 一样执行int strcmp(unsigned char *a, unsigned char *b)
。
当字符串因带符号 char c
而不同且char d
具有不同符号的值时,这会有所不同。
例如假设c < 0, d > 0
// 访问通过char *
并char
签名 c < d 为真 // 访问通过unsigned char *
c > d 为假
这会导致与返回的符号不同strcmp()
,从而影响排序字符串。
// Incorrect code when `char` is signed.
int strcmp(const char *a, const char *b) {
while (*a == *b && *a) { a++; b++; }
return (*a > *b) - (*a < *b);
}
// Correct code when `char` is signed or unsigned, 2's complement or not
int strcmp(const char *a, const char *b) {
const char *ua = a;
const char *ub = b;
while (*ua == *ub && *ua) { ua++; ub++; }
return (*ua > *ub) - (*ua < *ub);
}
[编辑]
这同样适用于读取和比较的二进制数据memcmp()
。
+0 在正确查看为 . 时结束了一个字符串unsigned char
。-0 不是终止字符串的空字符,即使作为有符号 char
它的值为零。
// Incorrect code when `char` is signed and not 2's complement.
// Conversion to `unsigned char` done too late.
int strcmp(const char *a, const char *b) {
while ((unsigned char)*a == (unsigned char)*b && (unsigned char)*a) { a++; b++; }
return ((unsigned char)*a > (unsigned char)*b) - ((unsigned char)*a < (unsigned char)*b);
}