代码之家  ›  专栏  ›  技术社区  ›  user2793162

将无符号字符数组传递给字符串函数

  •  3
  • user2793162  · 技术社区  · 11 年前

    假设我有一些utf8编码的字符串。在其内部,单词使用 ";" . 但是每个字符(除了 ";" )在这个字符串中有 utf8值>128 . 假设我将此字符串存储在内部 unsigned char 阵列:

    unsigned char buff[]="someutf8string;separated;with;";
    

    通过这个安全吗 buff strtok 作用(如果我只是想用 ";" 符号)。

    我担心的是 strtok (或者 strcpy )期望 char 指针,但在我的 字符串某些值将具有值>128 那么,这种行为被定义了吗?

    2 回复  |  直到 11 年前
        1
  •  2
  •   Keith Thompson    10 年前

    不,这不安全——但是 如果它编译 它几乎肯定会按照预期工作。

    unsigned char buff[]="someutf8string;separated;with;";
    

    这很好;该标准特别允许字符类型的数组(包括 unsigned char )使用字符串文本初始化。字符串文字的连续字节初始化数组的元素。

    strtok(buff, ";")
    

    这是一个 约束违反 ,需要编译时诊断。(这几乎等同于C标准所说的非法行为。)

    的第一个参数 strok 属于类型 char* ,但您传递的参数类型为 unsigned char* 。这两种指针类型不兼容,并且它们之间没有隐式转换。如果您的程序包含这样的调用(例如, gcc -std=c99 -pedantic-errors 拒绝。)

    许多C编译器在严格执行标准要求方面有些松懈。在许多情况下,编译器会对包含约束冲突的代码发出警告——这是完全有效的。但是,一旦编译器诊断出约束冲突并继续生成可执行文件,则该可执行文件的行为不受C标准的定义。

    据我所知,任何不拒绝此调用的实际编译器都会生成行为与您期望的一样的代码 字符* 无符号字符* 几乎肯定具有相同的表示形式,并且以与参数相同的方式传递 char 无符号字符 明确要求具有相同的非负值表示。即使值超过 CHAR_MAX 与您正在使用的编译器一样,编译器必须竭尽全力生成错误代码。如果系统不使用带符号整数的2补码,可能会遇到问题,但您不太可能遇到这样的系统。

    如果添加显式转换:

    strtok((char*)buff, ";")
    

    删除了约束冲突,可能会使任何警告静音——但行为仍然严格未定义。

    然而,在实践中,大多数编译器试图处理 烧焦 , signed char 无符号字符 几乎可以互换,一部分是为了迎合像你这样的代码,另一部分是因为他们必须全力以赴去做其他事情。

        2
  •  1
  •   Jonathan Leffler    11 年前

    根据C11标准(ISO/IEC 9899:2011§7.24.1字符串处理惯例,3,增加强调):

    对于本款中的所有功能,每个字符应为 解释为它具有 unsigned char (因此 可能的对象表示是有效的并且具有不同的值)。

    注:C99标准中没有此段落。

    所以我看不出有什么问题。

    推荐文章