【问题标题】:Casting from unsigned into signed char in C在C中从无符号转换为有符号字符
【发布时间】:2013-01-22 16:52:22
【问题描述】:

我正在使用lame 将输入raw pcm 流转换为mp3。该库中的编码函数在unsigned char 类型的数组中返回mp3 编码样本。这个 mp3 编码的流现在需要放置在一个 flv 容器中,该容器使用一个将编码样本写入 char 数组的函数。我的问题是我将数组从lameunsigned char 类型)传递到flv 库中。以下代码(仅象征性)说明了我的问题:

/* cast from unsigned char to char. */

#include <stdio.h>
#include <stdlib.h>

void display(char *buff, int len) {

  int i = 0;
  for(i = 0; i < len; i++) {
    printf("buff[%d] = %c\n", i, buff[i]);
  }
}

int main() {

  int len = 10;
  unsigned char* buff = (unsigned char*) malloc(len * sizeof(unsigned char));
  int i = 0;

  for(i = 65; i < (len + 65); i++) {
    buff[i] = (unsigned char) i;
    printf("char = %c", (char) i);
  }

  printf("Displaying array in main.\n");
  for(i = 0; i < len; i++) {
    printf("buff[%d] = %u\n", i, 'buff[i]');
  }

  printf("Displaying array in func.\n");
  display(buff, len);

  return 0;
}

我的问题:
1. 下面代码中的隐式类型转换(如将buff 传递给函数display 所证明的那样安全吗?可能会发生一些奇怪的行为吗?
2. 鉴于我别无选择,只能坚持现有的功能,是否有一种“安全”的方式将unsigned chars 的数组转换为chars?

【问题讨论】:

    标签: c casting char unsigned-char


    【解决方案1】:

    您似乎很担心类型安全,而无需它。由于这是 C 而不是 C++,因此没有强类型系统。只要从未设置“符号位”,从unsigned charchar 的转换通常是无害的。避免问题的关键是真正理解它们。 C中存在以下问题/特性:

    • 默认char 类型具有实现定义的签名。永远不应该对它的符号性做出任何假设,也不应该在任何类型的算术中使用它,尤其是按位运算。 char 只能用于存储/打印 ASCII 字母。切勿将其与十六进制文字混合使用,否则可能会出现细微的错误。
    • C 中的整数提升隐式地将所有小整数类型提升为可以保存其结果的整数类型,其中包括charunsigned char。实际上,这将始终是 int
    • 形式上,不同类型之间的指针转换可能是未定义的行为。但是 unsigned char 和 char 之间的指针转换实际上是安全的。
    • 字符文字 '\0' 等在 C 中属于 int 类型。
    • printf 和类似函数默认将所有字符参数提升为 int。

    您还强制转换 malloc 的 void* 结果,这在 C 中完全没有意义,并且在旧版本的 C 标准中可能有害,如果没有可见的函数原型,则将函数转换为“默认 int”。

    然后你有各种奇怪的逻辑相关的错误和不良做法,我已经修复但不会详细评论。使用这个修改后的代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    void display(const char *buff, int len) {
    
      for(int i = 0; i < len; i++) {
        printf("buff[%d] = %c\n", i, buff[i]);
      }
    }
    
    int main() {
    
      int len = 10;
      unsigned char* buff = malloc(len * sizeof(unsigned char));
    
      if(buff == NULL)
      {
        // error handling
      }
    
      char ch = 'A';
      for(int i=0; i<len; i++)
      {
        buff[i] = (unsigned char)ch + i;
        printf("char = %c\n", buff[i]); 
      }
    
    
      printf("\nDisplaying array in main.\n");
      for(int i = 0; i < len; i++) {
        printf("buff[%d] = %u\n", i, buff[i]);
      }
    
      printf("\nDisplaying array in func.\n");
      display((char*)buff, len);
    
      free(buff);
    
      return 0;
    }
    

    【讨论】:

    • 按位运算不涉及解释,尤其是没有符号。有什么问题,例如,c &amp; 0xdftoupper 一样?
    • 哦,I see。存在一个“仅理论上的”问题。
    【解决方案2】:

    unsigned char * 转换为char *(反之亦然)的唯一问题是它假定是一个错误。用演员表修复它。

    display((char *) buff, len);
    

    注意:这个演员表是不必要的:

    printf("char = %c", (char) i);
    

    这很好:

    printf("char = %c", i);
    

    %c 格式化程序以 int 参数开头,因为无论如何都不可能将 char 传递给 printf()(它总是会转换为 int,或者在极不可能的情况下, unsigned int.)

    【讨论】:

      【解决方案3】:

      从任何整数类型到任何其他相同或更大的整数类型的 C/C++ 强制转换都保证不会产生数据丢失。有符号和无符号字段之间的强制转换通常会产生上溢和下溢的危险,但您要转换的缓冲区实际上指向的原始数据的类型实际上是 void*。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-14
        • 1970-01-01
        相关资源
        最近更新 更多