【问题标题】:C++ - Incorrect ASCII value ("ë")C++ - 不正确的 ASCII 值(“ë”)
【发布时间】:2013-01-12 00:16:54
【问题描述】:

首先,我为我将犯的任何英语错误道歉,但 15 岁和法语并没有帮助......

我正在尝试借助文件格式规范 (http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html) 对 PNG 解码器进行编程,但遇到了一个奇怪的问题。

规范规定 PNG 文件的前 8 个字节始终包含以下(十进制)值:137 80 78 71 13 10 26 10。

当我测试这个简单的程序时:

int main() 
{
    ifstream file("test.png");

    string line;
    getline(file, line);

    cout << line[0] << endl;
}

输出是“ë”,它代表 ascii 表中的 137。很好,它匹配第一个字节。

但是,当我执行int ascii_value = line[0]; 时,输出值为-119,这不是正确的ascii 值。

当我用“e”之类的另一个字符尝试相同的操作时,它会输出正确的 ascii 值。

有人可以解释我做错了什么以及解决方案是什么吗?我个人认为这是扩展 ascii 表的问题,但我不确定。

谢谢大家! 我会将已签名的字符转换为未签名的字符

【问题讨论】:

  • 首先,std::string [] 运算符返回一个(对 a 的引用)char 而不是 int。根据您运行的语言环境以及您的限制文件所说的 -119 是一个完全有效的数字:)
  • 你的格式和英文都不错,不需要道歉:)
  • 有意或无意,第一行很搞笑,因为这篇文章中的英语比许多(如果不是大多数)在线帖子中的要好......
  • ë 137 采用什么编码方式?在 Unicode、iso8859-1 和 iso8859-15 中,ë 是 235。

标签: c++ png ascii decoder


【解决方案1】:

C++ 中的char 可以是有符号的也可以是无符号的1),这取决于它的实现。对于您的编译器(实际上,大多数情况下),它似乎已签名:

任何大于 128 的字符值都表示为负数。 -119 恰好对应于 unsigned 字符值 137。换句话说,以下成立:

unsigned char c = 137;
assert(static_cast<signed char>(c) == -119);

但请注意,这是特定于实现的,因此您通常不能依赖这些值。


1) 并且是signed charunsigned char不同类型

【讨论】:

  • 关于charsigned charunsigned char 的区别很好。
  • 是的。 3 个不同的 char 变体很容易被忽视,因为许多教科书/课程从不费心提及它。我还发现有趣的是,C 标准也特意说了同样的话。见 C11 6.2.5.14-15。从 6.2.5.15 开始:“实现应将 char 定义为与 signed charunsigned char 具有相同的范围、表示和行为”,然后脚注部分内容为“无论做出何种选择,@987654331 @ 是与其他两个不同的类型,并且与任何一个都不兼容。” C99 有相似的文字。
  • @Kevin 实际上我是在编写了一个程序之后才意识到这一点的,该程序在某些情况下使用特征测试类型相等性,并且由于char 既不是signed char 也不是unsigned char 而出现错误。
  • 我在追踪一个依赖于此的有趣 hack 时遇到了它,并且遇到了一个类,该类的方法具有 3 个重载,一个在 char*,一个在 unsigned char*,一个在 @ 987654337@。不用说这让我很震惊,因为我一直非常密切地关注 C++0x 的开发(阅读和理解大多数工作论文)并且觉得我非常了解该语言。
【解决方案2】:

当您允许符号扩展时会发生这种情况。扩展 ASCII 表中的字符设置了它们的高位(符号位)。

-119 是0x89。 137 也是0x89

试试

int ascii_value = line[0] & 0x00FF;

int ascii_value = (unsigned char)line[0];

【讨论】:

    【解决方案3】:

    您系统的char 类型是有符号的,这就是它的值可以为负数的原因。

    你需要明确并放弃标志:

    const unsigned char value = (unsigned char) line[0];
    

    请注意,您的机器似乎正在使用 two's complement 中的 -119 = 137。所以这些位本身确实是正确的,关键在于正确地解释它们。

    【讨论】:

      【解决方案4】:

      ASCII 仅涵盖 0 .. 127。ASCII 表中没有 137。

      也没有“扩展的 ASCII 表”这样的东西。有几十个(相互不兼容的)ASCII 扩展。哎呀,从技术上讲,即使是 Unicode 也是“扩展 ASCII”。

      您得到 -119,因为在您的编译器中 char 是有符号类型,涵盖从 -128 到 127 的值。(-119 是 137 - 256)。您可以通过显式转换为unsigned char 来获得您期望的值:

      int value = static_cast<unsigned char>(line[0]);
      

      【讨论】:

        【解决方案5】:

        137 = -119 = 0x89。如果你投(unsigned) (unsigned char)(line[0]),你会得到它来打印整数值137。

        char 类型(std::string 的基本类型)[通常] 是一个有符号值,范围为 -128-127。任何高于 127 的都是负数。

        【讨论】:

          【解决方案6】:

          C++ 没有指定char 是有符号还是无符号类型。这意味着“扩展的” ASCII 字符(0..127 范围之外的字符,其最高位已设置)可能被解释为负值;看起来这就是你的编译器所做的。

          要获得您期望的无符号值,您需要将其显式转换为 unsigned char 类型:

          int ascii_value = static_cast<unsigned char>(line[0]); // Should be 137
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-17
            • 2018-03-19
            • 1970-01-01
            相关资源
            最近更新 更多