Почему uint8_t и int8_t не работают с файловыми и консольными потоками?
$ 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 будут печатать
ничего без актеров
ничего, когда приведено к символу или без знака
8 при приведении к int или unsigned (хотя ASCII 'a' должно быть 97)
Мне каким-то образом удалось напечатать символ " ", но я забыл, в каком случае это было.
Почему я получаю эти странные результаты?
заметки для будущего читателя:
Вывод из ответа: только создавайте экземпляры потоков с символом (или одним из широких символов, упомянутых в стандарте), в противном случае вы не получите предупреждение компилятора и тихий сбой
очень грустно, что стандарт гарантирует эти вещи
Мораль этой истории: избегать C++
1 ответ
Декларация template std::basic_ifstream
является:
template<
class CharT,
class Traits = std::char_traits<CharT>
> class basic_ifstream;
Стандарт C++03 (21.1/1) требует, чтобы библиотека определяла специализации std::char_traits<CharT>
за CharT
знак равно char
, wchar_t
,
Стандарт C++11 (C++11 21.2/1) требует, чтобы библиотека определяла специализации std::char_traits<CharT>
за CharT
знак равно char
,char16_t
,char32_t
,wchar_t
,
Если вы создаете экземпляр std::basic_ifstream<Other>
с Other
ни один из 2[4] типов, назначенных Стандартом, к которому вы компилируете, поведение будет неопределенным, если вы сами не определите my_char_traits<Other>
как вам требуется, а затем создать экземплярstd::basic_ifstream<Other,my_char_traits<Other>>
,
Продолжение в ответ на комментарии ОП.
Запрос std::char_traits<Other>
не вызовет ошибок при создании экземпляра шаблона: шаблон определен так, что вы можете его специализировать, но использование по умолчанию (не специализированное) может привести к ошибкам Other
или действительно для любого данного CharT
где неправильные средства не соответствуют требованиям Стандарта для класса черт характера в соответствии с C++03 § 21.1.1 / C++11 § 21.2.1.
Вы подозреваете, что typedef может помешать выбору специализации шаблона для typedef
тип, то есть тот факт, что uint8_t
а также int8_t
являются typedefs для основных типов символов может привести к std::basic_ifstream<byte>
не то же самое, что std::basic_ifstream<FCT>
где FCT- псевдоним основного типа символа.
Забудь об этом подозрении.typedef
прозрачный Кажется, вы верите одному из typedefs int8_t
а также uint8_t
должно быть char
, в этом случае - если typedef как-то мешает разрешению шаблона - одно из неправильных действий basic_ifstream
проверенные вами экземпляры должны быть std::basic_ifstream<char>
Но как насчет того, что typedef char byte
безвреден? Это убеждение, что либо int8_t
или же uint8_t
знак равно char
ложно Вы найдете это int8_t
это псевдоним для signed char
в то время как uint8_t
это псевдоним для unsigned char
, Но ни signed char
ни unsigned char
тот же тип, что и char
:
C++03/11 § 3.9.1 / 1
Обычный символ, подписанный символ и неподписанный символ - это три различных типа
Так что оба 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
в вашей программе ни одно из приведенных вами приведений не даст неожиданного результата: SOMECAST
знак равно char
или же unsigned char
будет выводить a
, а такжеSOMECAST
знак равно int
или же unsigned int
будет выводить 97
,
Все плохое поведение возникает в результате basic_ifstream<CharT>
с CharT
некоторый тип, который Стандарт не гарантирует.