2009-10-11 2 views
0

Я хочу строку фиксированной длины из числа, как struct.pack, присутствующего в python, но в C++. Я думал о itoa (i,buffer,2), но проблема может заключаться в том, что его длина будет зависеть от платформы. Есть ли способ сделать его независимым от платформы?python struct.pack эквивалент в C++

ответ

3

Если вы ищете полное решение, подобное пакету структуры Python, вы можете проверить Google's Protocol Buffers Library. Используя это, вы позаботитесь о множестве проблем (например, endian-ness, языковой переносимости, совместимости с несколькими версиями) для вас.

+0

+1 Для ссылки –

1

Вам нужно определить целочисленный тип точной ширины через typedef; вы делаете это с определенной платформой. Если вы используете C99, int16_t предопределен в <stdint.h>. Вы можете бросить к этому типу, и введите представление в памяти переменный:

int16_t val = (int16_t) orig_val; 
void *buf = &val; 

Обратите внимание, что вам все равно придется иметь дело с байтами.

Если у вас нет C99, вы можете использовать тесты времени компиляции или времени выполнения. Для тестов времени компиляции рассмотрите использование autoconf, который уже вычисляет размеры различных примитивных типов, чтобы вы могли выбрать хороший тип во время компиляции. Во время выполнения просто выполните серию тестов sizeof. Обратите внимание, что это несколько неуместно для времени выполнения, так как тест всегда будет иметь тот же результат. В качестве альтернативы autoconf вы также можете использовать макросы идентификации компилятора/системы для теста времени компиляции.

0

++ путь C будет использовать stringstream:

stringstream ss; 
int number=/*your number here*/; 
ss<<number; 

и получить буфер вы бы использовать ss.str().c_str().

+0

-1 Это не дает строку с фиксированной длиной –

1

Вот старт:

typedef std::vector<uint8_t> byte_buffer; 

template <std::size_t N> 
void append_fixed_width(byte_buffer& buf, uintmax_t val) { 
    int shift = ((N - 1) * 8); 
    while (shift >= 0) { 
     uintmax_t mask = (0xff << shift); 
     buf.push_back(uint8_t((val & mask) >> shift)); 
     shift -= 8; 
    } 
} 

template <typename IntType> 
void append_bytes(byte_buffer& buf, IntType val) { 
    append_fixed_width<sizeof(IntType)>(buf, uintmax_t(val)); 
} 

int main() { // usage example 
    byte_buffer bytes; 
    append_bytes(bytes, 1); // appends sizeof(int) bytes 
    append_bytes(bytes, 1ul); // appends sizeof(unsigned long) bytes 
    append_bytes(bytes, 'a'); // appends sizeof(int) bytes :p 
    append_bytes(bytes, char('a')); // appends 1 byte 
    return 0; 
} 

Append_bytes будет добавлять любой тип целого числа в буфер байт представлены с использованием std::vector<uint8_t>. Значения упакованы в big endian байтовый заказ. Если вам нужно изменить это, затем настройте append_fixed_width для перемещения значения в другом порядке.

Эти функции создают необработанный байтовый буфер, так что кто-то расшифровывает его, он несет ответственность за то, что там есть. IIRC, это то, что делает struct.pack; другими словами, вызывающему абоненту struct.unpack необходимо предоставить такую ​​же строку формата. Вы можете написать вариант append_fixed_width для упаковки TLV вместо:

template <typename TagType, typename ValueType> 
void append_tlv(byte_buffer& buf, TagType t, ValueType val) { 
    append_fixed_width<sizeof(TagType)>(buf, uintmax_t(t)); 
    append_fixed_width<sizeof(std::size_t)>(buf, uintmax_t(sizeof(ValueType))); 
    append_fixed_width<sizeof(ValueType)>(buf, uintmax_t(val)); 
} 

Я принимаю бы серьезно взглянуть на Jeremy's suggestion хотя. Мне жаль, что он не существовал, когда я написал весь код двоичной упаковки, который у меня есть сейчас.

Смежные вопросы