【问题标题】:cast unsigned char * (uint8_t *) to const char *将 unsigned char * (uint8_t *) 转换为 const char *
【发布时间】:2011-10-23 23:11:26
【问题描述】:

我有一个带有 uint8_t * 参数的函数:

uint8_t* ihex_decode(uint8_t *in, size_t len, uint8_t *out)
{
    uint8_t i, hn, ln;

    for (i = 0; i < len; i+=2) {
        hn = in[i] > '9' ? (in[i]|32) - 'a' + 10 : in[i] - '0';
        ln = in[i+1] > '9' ? (in[i+1]|32) - 'a' + 10 : in[i+1] - '0';

        out[i/2] = (hn << 4 ) | ln;
    }

    return out;
}

我使用这个函数:

uint8_t data[SPM_PAGESIZE]; // SPM_PAGESIZE = 256 bytes
uint8_t sysex_data[SPM_PAGESIZE/2];
ihex_decode(data, strlen(data), sysex_data);

但在这种情况下,我的编译器 (avr-gcc) 返回一个警告:

main.c|89|警告:传递“strlen”参数 1 的指针目标符号不同 /usr/include/string.h|399|注意:预期为 'const char *' 但参数类型为 'uint8_t *'

所以,我通过类型转换数据 var 找到了解决方案:

ihex_decode(data, strlen((const char *)data), sysex_data);

警告消失了,但我想知道这个解决方案是否安全。

有没有更好的办法?

谢谢

【问题讨论】:

  • 你为什么使用uint8_t 来表示显然是char 的类型?
  • 因为我的程序是在微控制器上运行的。所以我不能有负值。
  • 这毫无意义。输入数据似乎是 ASCII 十六进制,所以它自然是 char。输出数据当然会保留为 uint8_t。
  • 所以你建议我把uint8_t *in改成char *in
  • 这里的问题不在于使用 uint8_t,问题在于人们认为 char 是某种神秘的魔法类型。如果你仔细检查,你会发现 ASCII 表中没有负数。因此,将 uint8_t 用于 ASCII 字符非常好,实际上它是最适合使用的类型。由于历史/不合逻辑的原因,C 标准碰巧使用 char 类型,这就是您收到警告的原因。只需对此类警告进行类型转换,uint8_t 更正确。

标签: c casting constants avr-gcc


【解决方案1】:

这是安全的。该错误与将 8 位无符号整数与字符混合有关,如果您仅使用 char,则这些字符是有符号的。

但是,我看到该函数接受uint8_t 并执行character 算术,因此它应该接受chars(或const chars,就此而言)。请注意,字符常量'c' 的类型为char,并且您在ihex_decode 内的表达式中混合了有符号和无符号,因此您必须小心避免溢出或将负数视为大正数。

最后的样式说明。由于in 没有被修改,它应该在参数中读取const uint8_t* in(或const char* in,同上)。另一个样式错误(可能导致非常严重的错误)是您接受lensize_t,但将i 循环变量声明为uint8_t。如果字符串长度超过 255 个字节怎么办?

【讨论】:

  • Char 可以有符号或无符号,这取决于实现,AFAIK。
  • 好的,@Rudy,加起来“在这种情况下”:)
  • 'c' 是一个整数。实际上,没有字符文字这样的东西,' ' 只是为程序员隐藏原始 ASCII 表的装饰性工具。如果您不相信我,请尝试打印sizeof('c')
  • 实际上,理论上它并不安全,尽管我所见过的现实世界的实现都不会有问题。 char 有可能超过 8 位。在这样的实现中,uint8_t 的大小必须与 char 相同(因为 sizeof(char) 为 1)但会忽略前几位。因此,如果转换为 char,实现可能会将 uint8_t 视为零但非零。因此 strlen 可以索引数组的末尾。
  • @JeremyP: uint8_t 是一个 exact width 类型,如果实现没有正好是 8 位的类型,那么它不必提供 @987654340 @.
【解决方案2】:

所有非 const * 都可以在 C 中安全地转换为 const *。这是保存。

【讨论】:

  • 但警告不是关于丢弃 const 限定符。
  • 警告是关于从uint8_t *char *的转换
  • 我回答的问题是:'我想知道这个解决方案是否安全。'。我回答了。
【解决方案3】:

这是安全的。警告(我认为)弹出是因为您正在从未签名转换为已签名。

【讨论】:

  • 我不完全确定它是否安全。如果没有后果,警告的目的是什么?
  • 不是因为 strlen() 需要一个 const char * ?
  • 不,char* 始终可以隐式转换为 const char*,因为它只会加强限制。但是,有符号 无符号可能会改变数据的解释并破坏某些算法,因此有一个警告。 0 在两种表示中是相同的,所以 strlen 应该可以正常工作。
【解决方案4】:

它的安全,char的范围

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多