0

在带有 c 的 Linux 中,我不明白当我读/写二进制缓冲区时char*和之间有什么区别?unsigned char*

什么时候不能用char*,什么时候需要用unsigned char*

4

1 回答 1

2

首先回忆 C 有unsigned char,signed charchar: 3 种不同的类型。 与或char具有相同的范围 。unsigned charsigned 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 指定的字符(转换为 an unsigned 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 charchar

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)

  1. 当字符串因带符号 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()

  1. 在不使用 2 补码的旧 C 实现中,可能有 2 个零:+0 和 -0(或陷阱)。

+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);
}
于 2020-06-18T05:38:21.740 回答