在使用C语言编写Linux程序时,我不理解在读写二进制缓冲区时
何时不能使用
char *
和 unsigned char *
之间的区别是什么?何时不能使用
char*
并需要使用 unsigned char*
?unsigned char *
与char *
相比的重要性并不在于I/O调用本身(它们都可以访问unsigned char *
),而在于编写数据和读取数据之前的数据设置和解释 - 请参见下面的memcmp()
。
什么情况下不能使用
char *
而需要使用unsigned char *
?
一个很好的例子是字符串相关的代码。
尽管<string.h>
中的函数在函数参数中使用char *
,但实现会像char
是unsigned char
一样执行,即使char
是有符号的。
对于本子句中的所有函数,每个字符都应解释为如果其类型为
unsigned char
(因此每种可能的对象表示都是有效的,并且具有不同的值)。C17dr §7.24.1 3
因此,即使char
是有符号的,像int strcmp(char *a, char *b)
这样的函数也会像执行int strcmp(unsigned char *a,unsigned char *b)
一样。
当char c
和char d
通过不同符号的值不同时,这将产生差异。
例如,假设c < 0,d > 0
// 通过char *
访问
c < d为true
// 通过unsigned char *
访问
c > d为false
这导致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不是用于终止字符串的null character,即使作为一个signedchar
它的值为零。
// 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);
}
char
是有符号还是无符号的,这取决于具体实现。而unsigned char
总是无符号的。 - Some programmer dude