【问题标题】:how to convert from unsigned byte to an integer?如何从无符号字节转换为整数?
【发布时间】:2020-04-07 23:09:12
【问题描述】:

我正在尝试读取一个包含无符号字节的文件,并且我正在尝试将它们读取为 [0,255] 的整数范围。

当我查看扩展 ascii 表时,当我读到“┌”时,它等于 218,但我的程序取为 195 或 226,我不知道为什么。

这个问题也发生在很多扩展部分(超过128个)的字符上。

为什么我不能读取 ASCII 等价物,我该如何解决这个问题? 谢谢回复。。

这是我的代码,


int main()
{
   unsigned int temp = 0;
   int bytesread;
   int fd = open("inputs.txt", O_RDONLY);

   if(fd == -1)
   {
       printf("An error occured.. \n");
       exit(-1);
   }
   else
   {
       bytesread = read(fd, &temp, 1);
   }

   printf("%d", temp);
   return 0;
}

【问题讨论】:

  • 你能提供文件的十六进制转储吗?
  • 我认为你的文件不在 ascii 中,你的字符 "┌" 存储为 94e2 0a8c 而不是 da0a
  • @Ôrel: 0a 是换行符,不是“┌”编码的一部分。
  • 如果您使用的是 Unix 系统,请键入 od -xa inputs.txt 以查看文件中十六进制的实际字节,或键入 od -tuC -a inputs.txt 以查看十进制的字节。如果文件很大,使用od -tuC -a inputs.txt | more 来控制输出。您可能会看到文件中的字节不是您想的那样。
  • 没有理由 unsigned int temp = 0;read(fd, &temp, 1)。推荐unsigned char temp = 0; 解决这个问题。

标签: c file byte ascii extended-ascii


【解决方案1】:

如果您看到很多 195,则输入可能是 UTF-8 character encoding

ASCII 最多只能达到 127 ,没有单一的标准“扩展 ascii”。有ISO-8859-1,但没有。或许你参考CP 437

从这里开始,您的前进道路将属于两种广泛的方法之一:

  • 使用适用于您的操作系统的工具或其他方式将文件从 UTF-8 转换为另一种编码,例如 CP437。
  • 在您的 C 程序中读取 UTF-8;您可以从头开始执行此操作,也可以使用预先存在的库。

【讨论】:

    【解决方案2】:

    该字符可能使用 UTF-8 编码存储在文件中。

    例如,字符 有一个Unicode 十六进制代码点250c,UTF-8 字节序列是e2 94 8ce2 等于您的小数 226,这表明您的角色实际上可能在附近的 Unicode 块中并采用 UTF-8 编码。

    正如 cmets 中所建议的,如果您提供文件的 hexdump 会非常有帮助,例如:

    hexdump -C inputs.txt
    

    【讨论】:

      【解决方案3】:

      这段代码

         bytesread = read(fd, &temp, 1);
      

      将一个字节读入unsigned int 的第一个字节,几乎可以肯定它比单个字节大。因此,您读取的数据最终在 int 值中的位置取决于您的系统。

      如果您要读取单个字节,通常使用[unsigned] char 会更容易,因此您总是知道它会在哪里结束。要将unsigned char 转换为int,您只需分配它:

      int main()
      {
         int fd = open("inputs.txt", O_RDONLY);
      
         if(fd == -1)
         {
             // perror() will tell you **WHAT** error occurred
             perror( "open()" );
             exit(-1);
         }
      
         // this is now an unsigned char
         unsigned char temp;
      
         // read() returns ssize_t, not int
         ssize_t bytesread = read( fd, &temp, sizeof( temp ) );
         if ( bytesread != sizeof( temp ) )
         {
             perror( "read()" );
             close( fd );
             exit( -1 );
         }
      
         close( fd );
      
         // there are a lot of ways to do this
         printf( "unsigned int value: %u\n", ( unsigned int ) temp );
      
         // this is another way - it prints the hex value
         printf( "hex value: %hhx\n", temp );
      
         // this prints the char value:
         printf( "char value: '%c'\n", temp;
      
         // this converts that unsigned char into an int:
         int intvalue = temp;
      
         // yes, it's that simple.
         printf( "int value: %d\n", intvalue  );
      
         return 0;
      }
      

      请注意,如果sizeof( int ) == sizeof( unsigned char ),结果可能会有所不同。在这种情况下,可能存在无法表示为 int 值的 unsigned char 值。

      【讨论】:

      • 这无法解释 OP 观察到的结果,因为 temp 被初始化为 0 并且通过修改对象的一个​​字节来修改对象是定义的行为(部分是实现定义的),因此结果必须将temp 中的低地址字节设置为读取字节,并且无论temp 中的字节顺序如何,对于输入字节218,这不会导致值195 或226。跨度>
      • @EricPostpischil “通过修改对象的一个​​字节来修改对象是已定义的行为(部分实现定义)” ---> 嗯,在独角兽领域,unsigned 带有填充(奇偶校验位) ,我有疑问。 IAC,OP 应该使用unsigned char temp;
      • @chux-ReinstateMonica: C 2018 6.2.5 2 说“除了位字段,对象由一个或多个字节的连续序列组成,其数量、顺序和编码是明确指定或实现定义。”因此,如果我知道对象中的字节,并将其中一个字节修改为我知道的值,我可以使用显式指定或实现定义的信息来计算表示的值。当然,这可能是一个陷阱值,而 using 可能会导致 C 标准未定义的行为,但那是另一回事。
      猜你喜欢
      • 1970-01-01
      • 2018-05-25
      • 2023-01-29
      • 2016-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      相关资源
      最近更新 更多