为什么 uint8_t 和 int8_t 不能与文件和控制台流一起使用?

use*_*358 -3 c++ types type-conversion ifstream uint8t

$ file testfile.txt\ntestfile.txt: ASCII text\n\n$ cat testfile.txt \naaaabbbbccddef\n\n#include <iostream>\n#include <fstream>\n#include <string>\n#include <cstdint>\ntypedef uint8_t byte; // <-------- interesting\ntypedef std::basic_ifstream<byte> FileStreamT;\nstatic const std::string FILENAME = "testfile.txt";\nint main(){\n    FileStreamT file(FILENAME, std::ifstream::in | std::ios::binary);\n    if(!file.is_open())\n        std::cout << "COULD NOT OPEN FILE" << std::endl;\n    else{\n        FileStreamT::char_type buff;\n        file.read(&buff,1);\n        std::cout << (SOMECAST)buff; // <------- interesting\n    }\n    std::cout << "done" << std::endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

根据 typedef 中的内容以及它转换为(或未转换)的内容,它会执行各种愚蠢的操作。

\n\n

它恰好适用于“typedef char”并且没有强制转换。(如预期,转换为 int 时为 97)

\n\n

uint8_t 和 int8_t 都会打印

\n\n
    \n
  • 没有演员就什么都没有

  • \n
  • 转换为 char 或 unsigned char 时没有任何内容

  • \n
  • 当转换为 int 或 unsigned 时为 8(尽管 ASCII \'a\' 应为 97)

  • \n
\n\n

我以某种方式设法打印了“\xef\xbf\xbd”字符,但忘记了它是哪种情况。

\n\n

为什么我会得到这些奇怪的结果?

\n\n

给未来读者的注意事项:

\n\n

从给出的答案中得出的结论:仅使用 char (或标准也提到的宽字符之一)实例化流,否则您不会收到编译器警告和静默失败

\n\n

令人遗憾的是,该标准保证了这些事情

\n\n

这个故事的寓意:避免使用 C++

\n

Mik*_*han 5

的声明template std::basic_ifstream是:

\n\n
template< \n    class CharT, \n    class Traits = std::char_traits<CharT>\n> class basic_ifstream;\n
Run Code Online (Sandbox Code Playgroud)\n\n

C++03 标准 (21.1/1) 要求库定义= ,std::char_traits<CharT>的特化。CharTcharwchar_t

\n\n

C++11 标准 (C++11 21.2/1) 要求库定义= 、、、std::char_traits<CharT>的特化。CharTcharchar16_tchar32_twchar_t

\n\n

如果您实例化时不std::basic_ifstream<Other>使用Other您正在编译的标准指定的 2[4] 种类型之一,则行为将是未定义的,除非您自己\n根据my_char_traits<Other>需要进行定义,然后实例化\n std::basic_ifstream<Other,my_char_traits<Other>>

\n\n

继续回应OP的评论。

\n\n

请求std::char_traits<Other>不会引发模板实例化\n错误:定义模板是为了可以对其进行专门化,但是\n默认(非专门化)实例化很可能对于\n甚至对于任何给定的都是错误的,其中错误的方法不满足\n标准对每个 C++03 \xc2\xa7 21.1.1/C++11 \xc2\xa7 21.2.1 的字符特征类的要求OtherCharT

\n\n

您怀疑 typedef 可能会阻碍为 -ed 类型选择模板专门化,即和是基本字符类型的 typedef,typedef这一事实可能会导致与 不同,其中FCT是别名基本字符字符类型。uint8_tint8_tstd::basic_ifstream<byte>std::basic_ifstream<FCT>

\n\n

忘记那个怀疑吧。typedef是透明的。看来您相信typedef 之一并且int8_t必须uint8_tchar,在这种情况下 - 除非 typedef 以某种方式干扰模板解析 -basic_ifstream您测试过的任何行为不当的实例都必须是std::basic_ifstream<char>

\n\n

但事实上它typedef char byte是无害的呢?int8_t认为 \或uint8_t=都不正确的信念char。你会发现\nis 是 whileint8_t的别名,是 的别名。\n但是 和都不是同一类型:signed charuint8_tunsigned charsigned charunsigned charchar

\n\n

C++03/11\xc2\xa7 3.9.1/1

\n\n
\n

普通 char、signed char 和 unsigned char 是三种不同的类型

\n
\n\n

因此char_traits<int8_t>, 和char_traits<uint8_t>都是默认的、\n非专业化的模板实例char_traits,你\n无权期望它们满足\n标准的字符特征要求。

\n\n

您没有发现任何不当行为的一个测试用例是byte= char。\n那是因为char_traits<char>是库提供的\n标准专业化。

\n\n

您观察到的所有不当行为与\n您已替换的类型之间的联系SOMECAST

\n\n
std::cout << (SOMECAST)buff; // <------- interesting\n
Run Code Online (Sandbox Code Playgroud)\n\n

没有。由于您的测试文件包含 ASCII 文本, \n这是标准保证\n读取它basic_ifstream<char>的唯一实例。basic_ifstream如果您在程序中使用读取该文件,typedef char byte\n那么您所说的替换的任何转换都不会产生意外的\n结果:SOMECAST= charorunsigned char将输出a,并且\n SOMECAST= intorunsigned int将输出97

\n\n

所有不当行为都源于basic_ifstream<CharT>使用CharT标准不保证的某种类型进行实例化。

\n