使用无符号字符指针(unsigned char*)和字符串函数(如strcpy)

3

我现在回忆起来,在我的代码中有些地方可能会将unsigned char*变量作为参数传递给像strcpystrtok这样期望char *的函数。我的问题是:这是个坏主意吗?它可能导致问题吗?

例如:

unsigned char * x = // .... some val, null terminated
unsigned char * y = // ... same here;
strcpy(x,y); // ps assuming there is space allocated for x

e.g., unsigned char * x = strtok(NULL,...)


你的问题描述不够清晰。建议提供一个最小化的代码案例,以便于定位编译错误或者其他问题。 - πάντα ῥεῖ
一般来说,我想知道将unsigned char *传递给期望char *的函数是否是一个好主意?(我不明白为什么会被踩) - user2793162
c++”标签去哪了?不感兴趣C++的答案,或者错误地假设它必须与C的答案相同? - Ben Voigt
@BenVoigt:是的,我更感兴趣的是C语言的答案 - 而且认为对于C++来说也应该类似。 - user2793162
嗯,C++ 在这方面大多与 C 兼容,但是规则还是有一些重要的差异。 - Ben Voigt
@BenVoigt:好的,基本上我的问题现在可以是:用哪个缓冲区来保存UTF-8?unsigned char * 还是 char *?如果我使用unsigned char *,哪些字符串函数不会出错?(我将浏览答案,看是否有对这个问题的回答) - user2793162
3个回答

2

在你转换指针后,它保证是可行的,因为“严格别名规则”对通过signedunsigned变量查看同一对象有一个特殊的例外。

请参见此处了解该规则。该页面上的其他答案也进行了解释。


@dmcr_code:嗯,你可能有一个编译器,其中“char”是“unsigned char”,而不是“signed char”。标准没有说明未经限定的“char”是带符号的还是无符号的。一般来说,只有在转换指针时,这样的代码才是可移植的。 - Ben Voigt
我有点困惑,因为未来我可能想使用UTF 8和无符号字符作为缓冲区 - 所以我想知道会发生什么情况 - 但显然有些普通的字符串函数也不会有用。但strtok应该没问题,因为分隔符是ASCII字符。 - user2793162
@dmcr_code:UTF-8 可以很好地与大多数为单字节字符串设计的函数配合使用。 - Ben Voigt
是的,但我的怀疑来自于我意识到我可能在所有地方都使用了unsigned char*,即使缓冲区本身应该包含ASCII值-所以这应该不是问题,对吧?另外,就像我说的,我可能没有进行强制转换,但也没有遇到任何问题。你建议我对此做些什么吗? - user2793162
@Ben Voigt:“即使这些字符串函数期望的是char*,它们在无符号字符缓冲区上也能正常工作。”-> 如果无符号缓冲区包含ASCII字符,那么这很简单,就像我的情况一样。但如果值是非ASCII字符呢?(但仍然以null结尾) - user2793162
显示剩余9条评论

2
C语言的别名规则对于有符号/无符号变量和一般字符访问有例外。所以这里没有问题。
引用标准中的一段话:

一个对象的存储值只能被具有以下类型之一的lvalue表达式访问:
- 与对象的有效类型兼容的类型
- 与对象的有效类型兼容的限定版本的类型
- 与对象的有效类型相应的带符号或无符号类型
- 与对象的有效类型的限定版本相应的带符号或无符号类型
- 包含上述类型之一的聚合或联合类型(包括子聚合或包含联合体的成员,递归地),或
- 字符类型

所有标准库函数都将任何char参数视为unsigned char,因此传递char*、unsigned char*或signed char*是相同的。
引用的介绍:

对于本子句中的所有函数,每个字符都将被解释为具有unsigned char类型(因此,每个可能的对象表示都是有效的并且具有不同的值)。

但是,如果您弄错了符号,则编译器应该会发出警告,特别是如果您启用了所有警告(您应该始终这样做)。

我的标准中唯一关于将unsigned char视为处理的内容是:“许多库函数的描述依赖于C标准库的签名和语义。在所有这些情况下,都应省略任何使用限定符的限制。”(该问题也被标记为“c ++”)。无论如何,这是一个好消息。 - Ben Voigt
嗯,我已经找到了C语言的参考资料。由于C和C++都尽量避免不必要的不兼容性,所以应该有类似的东西适用于C++。不过也许你引用的内容就足够了... - Deduplicator
请翻译以下有关编程的内容,从英文到中文。只返回翻译后的文本:附注:这是针对C语言的,我认为去掉C++标签可能没有影响。 - user2793162
@dmcr:如果答案对两者都相同,而且已经有了答案,那为什么还要费事呢?不过,我有时会添加C或C++标签,如果两者都适用的话。这样可以更好地搜索。 - Deduplicator
@giorgim:不,charsigned charunsigned char(以及指向它们的指针)是不同的类型,只是所有标准库函数都将char处理为unsigned整数类型。 - Deduplicator

0
转换 unsigned char *char *(或反之亦然)的唯一问题是它本应该是一个错误。使用强制类型转换来解决它。

e.g,

function((char *) buff, len);

话虽如此,strcpy需要有空字符(\0)才能正常工作。另一种选择是使用memcpy

但是你不应该使用带有字符串处理函数的unsigned char数组。在C中,字符串是char数组,而不是unsigned char数组。由于传递给strcpy会丢弃无符号限定符,因此编译器会发出警告。

总的来说,当你没有必要时,不要将事物设为无符号。


如果这是一个C编译器,它不应该关心。 - Engineer2021
1
通常情况下,如果不必要的话,也不要将事物标记为有符号。 - 4pie0
@staticx,简单回答一下:在这种情况下,strcpy函数是否能正常工作? - 4pie0
有些库将unsigned char*用作字符串,SQLite就是一个例子。那么,为什么char会有带符号/无符号的对应项? - Joker_vD
1
strcpy和所有其他C字符串/字符处理函数的定义是按照unsigned char来工作的。所以,没有问题。 - Deduplicator
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接