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

时间:2013-07-26 06:09:34

标签: c++ types type-conversion ifstream uint8t

$ file testfile.txt
testfile.txt: ASCII text

$ cat testfile.txt 
aaaabbbbccddef

#include <iostream>
#include <fstream>
#include <string>
#include <cstdint>
typedef uint8_t byte; // <-------- interesting
typedef std::basic_ifstream<byte> FileStreamT;
static const std::string FILENAME = "testfile.txt";
int main(){
    FileStreamT file(FILENAME, std::ifstream::in | std::ios::binary);
    if(!file.is_open())
        std::cout << "COULD NOT OPEN FILE" << std::endl;
    else{
        FileStreamT::char_type buff;
        file.read(&buff,1);
        std::cout << (SOMECAST)buff; // <------- interesting
    }
    std::cout << "done" << std::endl;
}

取决于typedef中的内容以及它被转换为(或不转换)的内容,它会执行各种愚蠢的事情。

它恰好与'typedef char'一起使用而且没有强制转换。 (按照预期将97转换为int)

uint8_t和int8_t都将打印

  • 没有演员阵容

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

  • 8当转换为int或unsigned时(虽然ASCII'a'应为97)

我设法打印了一个“ ”字符,但忘记了它是什么情况。

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

未来读者的注意事项:

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

标准保证这些事情是非常可悲的

故事的道德:避免使用C ++

1 个答案:

答案 0 :(得分:2)

template std::basic_ifstream的声明是:

template< 
    class CharT, 
    class Traits = std::char_traits<CharT>
> class basic_ifstream;

C ++ 03 Standard(21.1 / 1)要求库定义特化 std::char_traits<CharT> = CharTchar的{​​{1}}。

C ++ 11标准(C ++ 11 21.2 / 1)要求库定义特化 wchar_t = std::char_traits<CharT>CharTcharchar16_t的{​​{1}}。

如果您使用char32_t实例化wchar_t而不是其中之一 由您编制的标准提名的2 [4]种类型 除非你自己,否则行为将是不确定的 根据需要定义std::basic_ifstream<Other>然后实例化 Other

以回应OP的评论。

请求my_char_traits<Other>不会激发模板实例化 错误:模板定义为,以便您可以将其专门化,但是 std::basic_ifstream<Other,my_char_traits<Other>>的默认(非特定)实例化很可能错误 或者确实对于任何给定的std::char_traits<Other>,其中错误意味着不满足 标准对每个C ++的角色特征类的要求03§21.1.1/ C ++11§21.2.1

您怀疑typedef可能会阻碍模板特化的选择 对于Other - ed类型,即CharTtypedef这一事实 是基础字符类型的typedef可能导致uint8_tint8_t不同,其中 FCT 是别名的基本字符类型。

忘记这种怀疑。std::basic_ifstream<byte>是透明的。你似乎相信一个 typedef std::basic_ifstream<FCT>typedef必须是int8_t,在这种情况下 - 除非 typedef以某种方式与模板分辨率相关 - 您测试过的行为不当uint8_t实例之一 必须是char

但是basic_ifstream无害的事实呢?那种信念 std::basic_ifstream<char>typedef char byte = int8_t为假。你会发现uint8_tchar的别名,而int8_tsigned char的别名。 但uint8_tunsigned charsigned char的类型不同:

C ++ 03 /11§3.9.1/ 1

  

Plain char,signed char和unsigned char是三种不同的类型

因此unsigned charchar都是默认值, 模板char_traits<int8_t>的非专业化实例化,你有 没有权利期望他们满足该标准的要求 角色特征

您发现没有错误行为的一个测试用例是char_traits<uint8_t> = char_traits。 这是因为byte是提供的标准专业化 由图书馆。

你观察到的所有不端行为与之间的联系 您已替换char的类型:

char_traits<char>

没有。由于您的测试文件包含ASCII文本,SOMECAST 是标准所保证的std::cout << (SOMECAST)buff; // <------- interesting 唯一的实例化 阅读它。如果您在程序中使用basic_ifstream<char>读取文件 那么你说你替换的演员都没有意外 结果:basic_ifstream = typedef char byteSOMECAST将输出char,并且 unsigned char = aSOMECAST将输出int

所有不当行为都来自unsigned int97的实例化 标准不保证的某种类型。