为什么uint8_t和int8_t不支持文件和控制台流? [英] Why doesn't uint8_t and int8_t work with file and console streams?

查看:779
本文介绍了为什么uint8_t和int8_t不支持文件和控制台流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  $ file testfile.txt 
testfile.txt:ASCII文本

$ 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中的内容以及它所转换的内容cast),它做了各种愚蠢的事情。



它适用于'typedef char'和没有转换。 (97,如预期的那样转换为int)



uint8_t和int8_t将打印




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






为什么会出现这些奇怪的结果?



对未来读者的注释:



从给出的答案中获取:仅使用char(或标准中也提及的一个宽字符)实例化流,否则你得不到编译器警告和无声失败



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



故事:避免C ++


解决方案

声明 template std :: basic_ifstream 是:

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

C ++ 03标准(21.1 / 1)需要库来定义特殊化
std :: char_traits< CharT> for CharT = char wchar_t



C ++ 11标准(C ++ 11 21.2 / 1)定义特殊化code> CharT = 定义特殊化 std :: char_traits& char char16_t char32_t wchar_t



如果您实例化 std :: basic_ifstream< Other> 不是
之一由标准提交的2 [4]类型,然后
行为将是未定义的,除非你自己
定义 my_char_traits< Other> ,然后实例化
std :: basic_ifstream< Other,my_char_traits< Other>< / code



请求<$> $

c $ c> std :: char_traits< Other>
不会引起模板实例化
错误:模板定义为,以便您可以专门化,但
其他
或任何给定的错误 > CharT
,其中错误意味着不满足
标准对字符traits类的要求每个C ++ 03§21.1.1 / C ++ 11§21.2.1



您怀疑typedef可能阻碍模板专业化的选择
typedef 类型,即事实 uint8_t int8_t
是基本字符类型的typedef可能会导致 std :: basic_ifstream< byte>
不等于 std :: basic_ifstream< FCT>


是别名的基本字符类型。



忘记这个猜测。 typedef 是透明的。您似乎相信
中的一个 typedefs int8_t uint8_t 必须 char ,在这种情况下 - 除非
typedef以某种方式干扰模板解析 -
错误行为之一 basic_ifstream code>
必须 std :: basic_ifstream< char>



但是, typedef char byte 是无害的呢?
int8_t uint8_t = char 为false。您会发现 int8_t
signed char 的别名,而 uint8_t unsigned char 的别名。
但是 signed char 也不是 unsigned char / code>:



C ++ 03/11§3.9.1 / 1


普通字符,signed char和unsigned char是三种不同的类型


char_traits< int8_t> char_traits< uint8_t> 是默认值,
未特殊化,模板实例化 char_traits ,并且您有
无权期望他们符合该标准对
字符特征的要求



byte = char 的一个测试用例中没有发现不良行为。
这是因为 char_traits< char> 是由库提供
的标准专业化。



您所观察到的所有不当行为与您用 SOMECAST 替换的
类型之间的关系:

  std :: cout< (SOMECAST)buff; //< -------- interesting 

由于你的测试文件包含ASCII文本, basic_ifstream< char>
是一个唯一的实例化 basic_ifstream 该标准保证
的读取。如果您在程序
中使用 typedef char byte 读取文件,那么您说的替换的任何转换都不会有意外的
结果: code> SOMECAST
= char unsigned char 将输出 a
SOMECAST = int unsigned int 将输出 97



code> basic_ifstream< CharT> 与 CharT
标准不保证的某种类型。


$ 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;
}

Depending on what is in the typedef and what is it casted to (or not casted), it does all sorts of stupid things.

It happens to work with 'typedef char' and no cast. (97 when casted to int, as expected)

Both uint8_t and int8_t will print

  • nothing without cast

  • nothing when casted to char or unsigned char

  • 8 when casted to int or unsigned (although ASCII 'a' should be 97)

I somehow managed to print a "�" character, but forgot which case it was.

Why do I get these strange results?

notes for the future reader:

takeaway from the answer given: only instantiate streams with char (or one of the wide characters also mentioned by the standard), otherwise you get no compiler warning and silent failure

it is very sad that the standard warrants these things

moral of the story: avoid C++

解决方案

The declaration of template std::basic_ifstream is:

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

The C++03 Standard (21.1/1) requires the library to define specializations of std::char_traits<CharT> for CharT = char, wchar_t.

The C++11 Standard (C++11 21.2/1) requires the library to define specializations of std::char_traits<CharT> for CharT = char,char16_t,char32_t,wchar_t.

If you instantiate std::basic_ifstream<Other> with Other not one of the 2[4] types nominated by the Standard to which you are compiling then the behaviour will be undefined, unless you yourself define my_char_traits<Other> as you require and then instantiate std::basic_ifstream<Other,my_char_traits<Other>>.

CONTINUED in response to OP's comments.

Requesting an std::char_traits<Other> will not provoke template instantiation errors: the template is defined so that you may specialize it, but the default (unspecialized) instantiation is very likely to be wrong for Other or indeed for any given CharT, where wrong means does not satisfy the the Standard's requirements for a character traits class per C++03 § 21.1.1/C++11 § 21.2.1.

You suspect that a typedef might thwart the choice of a template specialization for the typedef-ed type, i.e. that the fact that uint8_t and int8_t are typedefs for fundamentals character types might result in std::basic_ifstream<byte> not being the same as std::basic_ifstream<FCT>, where FCT is the aliased fundamental character type.

Forget that suspicion.typedef is transparent. It seems you believe one of the typedefs int8_t and uint8_t must be char, in which case - unless the typedef was somehow intefering with template resolution - one of the misbehaving basic_ifstream instantiations you have tested would have to be std::basic_ifstream<char>

But what about the fact that typedef char byte is harmless? That belief that either int8_t or uint8_t = char is false. You will find that int8_t is an alias for signed char while uint8_t is an alias for unsigned char. But neither signed char nor unsigned char is the same type as char:

C++03/11 § 3.9.1/1

Plain char, signed char, and unsigned char are three distinct types

So both char_traits<int8_t> and char_traits<uint8_t> are default, unspecialized, instantiations of template char_traits and you have no right to expect that they fulfill that Standard's requirements of character traits.

The one test case in which you found no misbehaviour was for byte = char. That is because char_traits<char> is a Standard specialization provided by the library.

The connection between all the misbehaviour you have observed and the types that you have substituted for SOMECAST in:

std::cout << (SOMECAST)buff; // <------- interesting

is none. Since your testfile contains ASCII text, basic_ifstream<char> is the one and only instantiation of basic_ifstream that the Standard warrants for reading it. If you read the file using typedef char byte in your program then none of the casts that you say you substituted will have an unexpected result: SOMECAST = char or unsigned char will output a, and SOMECAST = int or unsigned int will output 97.

All the misbehaviour arises from instantiating basic_ifstream<CharT> with CharT some type that the Standard does not warrant.

这篇关于为什么uint8_t和int8_t不支持文件和控制台流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆