Я пытаюсь вывести UUID, хранящийся в виде вектора байтов, в виде шестнадцатеричной строки с тире. Если какой-либо отдельный байт имеет начальный ноль, моя выходная строка пропускает его. Я использую std::setw(2) и все еще получаю такое поведение.
Я попробовал следующий код:
#include <iomanip>
#include <iostream>
std::ostream& operator<<(std::ostream &os, const Id &id) {
std::ios oldState(nullptr);
oldState.copyfmt(os);
os << std::hex << std::uppercase << std::setfill('0') << std::setw(2);
for (int i = 0; i < 16; i++) {
os << (int)id.id_[i];
if (i == 3 || i == 5 || i == 7 || i == 9) os << '-';
}
os.copyfmt(oldState);
return os;
}
Мой ожидаемый результат будет примерно таким:
01020304-0102-0304-0506-AA0F0E0D0C0B
и вместо этого я получаю:
1234-12-34-56-AAFEDCB
Я явно делаю здесь что-то не так. Я пробовал очистить буфер и вставить тире постфактум, но все равно безуспешно.
Возможно, самое актуальное: Какие манипуляторы iomanip являются «липкими»? . И еще Что случилось с setw()? и «Постоянный» std::setw
@Yksisarvinen Это помогло. Мой вывод теперь в правильном формате.





Как пояснялось в комментариях, std::setw — это одноразовый манипулятор. Он работает только со следующим выходным элементом. После этого ширина потока сбрасывается до 0.
Исправить это достаточно просто: переместите setw в цикл.
В демонстрационных целях я создал struct Id.
// main.cpp
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <vector>
#include <initializer_list>
struct Id
{
Id(std::initializer_list<std::uint8_t> l)
: id_{ l }
{}
std::vector<std::uint8_t> id_;
};
std::ostream& operator<<(std::ostream& os, const Id& id) {
std::ios oldState(nullptr);
oldState.copyfmt(os);
os << std::hex << std::uppercase << std::setfill('0');
for (int i = 0; i < 16; i++) {
os << std::setw(2) << (int)id.id_[i]; // <===== setw goes here
if (i == 3 || i == 5 || i == 7 || i == 9) os << '-';
}
os.copyfmt(oldState);
return os;
}
int main()
{
Id id{
0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0xAA, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B
};
std::cout << id << '\n';
return 0;
}
Выход:
01020304-0102-0304-0506-AA0F0E0D0C0B
Я думаю, что создание функции для преобразования, а затем вызов ее в перегрузке более пригодно для повторного использования.
здесь код
#include <cstdint>
#include <iostream>
#include <array>
#include <string>
struct Id
{
std::array<uint8_t, 16> bytes;// std::array is same as normal array but more useful feature.
};
std::string uuid2rfc4122(const Id& uuid)
{
static char char2hex_table[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
std::string str;
str.reserve(36);//this prevent for reallocate memory from push_back
int pos = 0;
for (auto byte : uuid.bytes) { //this intend to do not use reference. Reference is actually pointer so their size is 8 bytes in 64bit system. it has overhead if we store reference pointer instead of value.
//1 byte represent by 2 hex character
str.push_back(char2hex_table[byte >> 4]); //0b1111'xxxx We don't need x. After shift value = 0b1111
str.push_back(char2hex_table[byte & 0x0f]);//0bxxxx'1111 After bitwiseAnd value = 0b0000'1111
++pos;
if (pos == 4 || pos == 6 || pos == 8 || pos == 10) {
str.push_back('-');
}
}
return str;
}
std::ostream& operator<<(std::ostream& os, const Id& id) {
os << uuid2rfc4122(id);
return os;
}
Вам нужно вызывать
setwдля каждой операции вывода, для которой должна быть установлена ширина (такos << std::setw(2) << static_cast<int>(id.id_[i]);). Не могу найти ни одного дубликата, который бы спрашивал об этом, вместо этого я вижу только вопросы, почему это так...