Я пытался понять, можно ли использовать ispanstream
для извлечения данных из буфера.
Допустим, у меня есть буфер символов, содержащий ряд разных переменных разных типов. Когда я извлекаю из потока переменную с размером, отличным от размера базового буфера, я получаю, что переменная назначения имеет значение 0; если вместо этого переменная назначения имеет тот же размер, что и буфер, она заполняется так, как я и ожидал.
Вот MWE:
#include <iostream>
#include <array>
#include <spanstream>
#include <cstdint>
union S
{
int32_t int32_;
uint64_t uint64_;
std::array<uint8_t, sizeof(uint64_t)> arr;
};
int main()
{
char underlyingBuf[15];
for (uint8_t i = 0; i < 15; i++)
underlyingBuf[i] = i + 100;
std::span<char, sizeof(underlyingBuf)> span{ underlyingBuf };
std::ispanstream iss(span);
S read_var{ 0LL };
for (size_t i = 0; i < sizeof(read_var.int32_); ++i)
iss >> read_var.arr[i];
//iss >> read_var.int32_;
std::cout.setf(std::cout.hex, std::cout.basefield);
std::cout.setf(std::cout.showbase);
std::cout << read_var.uint64_ << std::endl;
}
Здесь вывод этого кода — 0x67666564, но если я раскомментирую строку iss >> read_var.int32_;
(или если я запущу только ее вместо цикла for), вывод будет равен 0.
Я ожидал, что код выведет 0x67666564, если я запустил строку с комментариями вместо цикла for, и 0x6B6A6968, если я запустил его после цикла for.
ispanstream
?span
?read_var.int32_
устанавливается значение iss >> read_var.int32_;
в 0 вместо того, чтобы оставить его без изменений?Я относительно новичок в C++ (особенно в его более современных модах) и изо всех сил пытаюсь понять, в чем я ошибся.
Я получаю одинаковое поведение как с msvc, так и с gcc, поэтому я предполагаю, что именно так оно и должно вести себя. Спасибо!
как заметил @некоторый чувак-программист, мой MWE был немного непослушным в том, как я использовал объединение. Вот исправленный пример:
#include <iostream>
#include <array>
#include <spanstream>
#include <cstdint>
int main()
{
char underlyingBuf[15];
for (uint8_t i = 0; i < 15; i++)
underlyingBuf[i] = i + 100;
std::span<char, sizeof(underlyingBuf)> span{ underlyingBuf };
std::ispanstream iss(span);
int8_t var1{ 0L };
int32_t var2{ 0L };
iss >> var1 >> var2;
std::cout.setf(std::cout.hex, std::cout.basefield);
std::cout.setf(std::cout.showbase);
std::cout << var1 << "\t" << var2 << std::endl;
}
В этом случае выходные данные: var1 == d и var2 == 0. Почему var2 не присваивается содержимому буфера?
Спасибо, что указали на то, что я был слишком авантюрным в своем подходе. Я изменил пример, чтобы не использовать никаких объединений, но при извлечении в int32_t я все равно получаю то же самое поведение. Что я делаю не так? Более того, если я поменяю местами извлечения iss >> var2 >> var1;
, то var1 больше ничего не выведет.
Ваш второй пример считывает 100 (или «d») как символьное значение для var1, а затем не может прочитать десятичные числа в var2.
Хорошо, теперь я понял. Это не удается, потому что ispanstream
является потоком char
и поэтому он не может извлечь ничего, что больше байта, потому что не может неявно преобразовать его в char
при извлечении. Спасибо, Оо!
Буфер содержит «defghijklmnopqr».
iss >> var1 >> var2;
Тип var1
— int8_t
, что обычно signed char
. Таким образом, 'd' (или 100) считывается в var1
и предпринимается попытка прочитать целое число из строки efghijklmnopqr
. Это не целое число, поэтому значение var2
не меняется и устанавливается бит ошибки: https://godbolt.org/z/ME7ozdTGY
В C++ нельзя использовать каламбур через объединения. Последний записанный член объединения — единственный член, из которого вы можете читать. Запись одному участнику и чтение другому приводит к неопределенному поведению.