Мне нужно напечатать переменное количество символов в виде шестнадцатеричного значения во встроенной системе для отладки.

В C мне нужно напечатать переменное количество символов в виде шестнадцатеричного значения во встроенной системе для отладки. Поскольку это часть макроса трассировки отладки, я хочу избежать циклов или другой логики, с которой printf не может справиться. Я также не хочу объявлять какие-либо новые переменные, чтобы предотвратить проблемы Heisenbug. Выходное пространство также является проблемой, поэтому я хочу вывести его в шестнадцатеричном формате.

uint8_t* buffer;
uint8_t length;

MakeString(*message, &buffer, &length);  //Function that puts some values in buffer and sets length

Я ищу printf, который может принимать буфер и длину для создания чего-то вроде:

0x1A1B1C0A02

для значений {1A,1B,1C,0A,02} и длины = 5

Я знаю, что %.*s или %* могут обрабатывать переменные размера. Есть ли способ сделать это без цикла for/while?


person MountainLogic    schedule 11.01.2015    source источник
comment
какой тип * сообщения? как определяется его длина?   -  person Jasen    schedule 11.01.2015
comment
В качестве альтернативы вы можете написать свою сложную функцию с циклами в отдельном файле .c, а затем использовать макрос для ее вызова. В отладочной версии макрос должен вызывать функцию, а в релизной ничего не делать.   -  person Mark Shevchenko    schedule 11.01.2015
comment
Если вы не используете внутрисхемный аппаратный эмулятор, НЕТ НИКАКОЙ СПОСОБНОСТИ избежать Heisenbug. Если вы добавите что-нибудь в свой ошибочный код, вы можете переместить очевидные побочные эффекты вашей ошибки в другое место или сделать ее доброкачественной ошибкой. Возможно, вам не захочется объявлять новые переменные, но вы не избежите использования стека.   -  person Weather Vane    schedule 11.01.2015
comment
Параметры функции @MarkShevchenko являются локальными переменными   -  person Jasen    schedule 21.08.2016


Ответы (2)


В прошлом я использовал такие вещи, как следующее:

void
to_hex(char *output, size_t out_len, uint8_t const *input, size_t in_len)
{
        static const char digits[] = "0123456789abcdef";
        if (out_len < 1) {
                return;
        }

        --out_len; /* reserve space for that NUL terminator */
        while (out_len > 1 && in_len) {
                *output++ = digits[(*input & 0xF0) >> 4];
                *output++ = digits[*input & 0x0F];
                out_len -= 2;
                ++input, --in_len;
        }
        if (in_len) {
                *output++ = digits[(*input & 0xF0) >> 4];
        }
        *output = '\0';
}

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

В системах, над которыми я работал, не было реализации printf или sprintf, поэтому мы обычно создавали собственный шестнадцатеричный код дампа.

person D.Shawley    schedule 11.01.2015
comment
Думаю, он пропустил там while. - person Jasen; 21.08.2016
comment
@Jasen ... Я был удивлен, когда это тоже было принято. Я предполагаю, что развертывание цикла довольно тривиально, если вы ограничиваете длину ввода. - person D.Shawley; 22.08.2016

no.

Я думаю, вы могли бы повесить что-то из прерывания буфера последовательного порта, которое считывает байт из буфера и выдает два байта на последовательный порт... никаких петель per se.

или сделать что-то подобное (этот пример действителен только для длины от 0 до 10)

int printbuf(unsigned char*buffer,int length)
{
     #define b(x) buffer[x<length?x:0]
     return printf("%02h%02h%02h%02h%02h%02h%02h%02h%02h%02h%02h"+4*(10-length)
           ,b(0),b(1),b(2),b(3),b(4),b(5),b(6),b(7),b(8),b(9));
     #undef b
}

но сам sprintf содержит циклы...

person Jasen    schedule 11.01.2015