说我有一些utf8编码的字符串。在其中,单词使用";"
分隔。
但是此字符串中的每个字符(";"
除外)都具有 utf8值> 128 。
假设我将此字符串存储在unsigned char
数组中:
unsigned char buff[]="someutf8string;separated;with;";
将此buff
传递给strtok
函数是否安全? (如果我只想用";"
符号提取单词)。
我担心的是strtok
(或strcpy
)期望char
指针,但在我的内心
字符串一些值将具有值> 128。
那么这个行为定义了吗?
答案 0 :(得分:3)
不,它不安全 - 但如果它编译它几乎肯定会按预期工作。
unsigned char buff[]="someutf8string;separated;with;";
这很好;该标准特别允许使用字符串文字初始化字符类型(包括unsigned char
)。字符串文字的连续字节初始化数组的元素。
strtok(buff, ";")
这是约束违规,需要编译时诊断。 (那就像C标准那样接近说某些东西是非法的。)
strok
的第一个参数属于char*
类型,但您传递的是unsigned char*
类型的参数。这两种指针类型不兼容,它们之间没有隐式转换。符合标准的编译器可能会拒绝您的程序,如果它包含这样的调用(例如,gcc -std=c99 -pedantic-errors
拒绝它。)
许多C编译器在严格执行标准要求方面有些松懈。在许多情况下,编译器会对包含约束违规的代码发出警告 - 这完全有效。但是,一旦编译器诊断出违反约束并继续生成可执行文件,那么C标准就不会定义该可执行文件的行为。
据我所知,任何不拒绝此调用的实际编译器都会生成与您期望的行为相同的代码。指针类型char*
和unsigned char*
几乎肯定具有相同的表示形式,并且以与参数相同的方式传递,并且类型char
和unsigned char
明确要求具有相同的非负值的表示。即使对于超过CHAR_MAX
的值,就像您正在使用的值一样,编译器也不得不竭力生成行为不端的代码。对于没有使用2-s补码的系统,你可能会遇到问题,但是你不太可能遇到这样的系统。
如果添加显式强制转换:
strtok((char*)buff, ";")
删除约束违规并且可能会使任何警告静音 - 但行为仍然是严格未定义的。
但实际上,大多数编译器会尝试几乎互换地处理char
,signed char
和unsigned char
,部分原因是为了迎合像您这样的代码,部分原因是因为他们会这样做我们必须竭尽全力去做其他事情。
答案 1 :(得分:1)
根据C11标准(ISO / IEC 9899:2011§7.24.1字符串处理约定,¶3,强调增加):
对于本子条款中的所有功能,每个字符应为 被解释为好像它有
unsigned char
类型(因此每个 可能的对象表示是有效的,并且具有不同的值。)
注意:C99标准中没有此段落。
所以我没有看到问题。