sprintf вызывает проблемы со временем?

У меня возникла проблема при использовании sprintf.

Мне нужно, чтобы массив символов выглядел так: g;cmd;arg;e;, где arg получает начальные нули, поэтому он всегда имеет длину 3 символа, а cmd получает начальные нули, поэтому он всегда имеет длину 15 символов. Например, если cmd = 20 и arg = 3749, мне нужен массив символов, который выглядит так: g;020;000000000003749;e;. И arg, и cmd являются целыми числами.

Сначала я сделал это довольно неэффективным способом, но я изменил его на что-то гораздо более простое, используя sprintf, потому что мне нужно было, чтобы мой код был быстрее. И мой исходный код, и мои изменения можно найти на github.

Моя текущая реализация выглядит так:

#define cmdMsgLength 3
#define argMsgLength 15
#define totalFormatedMsgLength (2+cmdMsgLength+1+argMsgLength+3)
#define msgFormater "g;%03d;%015d;e;"

char msgToSendFormated[totalFormatedMsgLength];
void sendMsg(int _cmd, int _arg) {
 sprintf(msgToSendFormated, msgFormater, _cmd, _arg);
 Serial.print(msgToSendFormated);
}

Это, казалось, работало хорошо, пока мой UC также не должен был контролировать 4 ESC. Честно говоря, я не могу найти никакой связи между ними, но похоже, что эта реализация приводит к проблемам с регуляторами скорости, где, конечно, время очень важно. ESC запрограммированы правильно, но при использовании функции Arduino servo.writeMicroseconds для их приведения в действие они, кажется, действуют случайным образом. После довольно большого количества тестов только это изменение в моем коде, похоже, вызывает проблему. Поскольку этот фрагмент кода настолько прост, а старый код (проверьте ссылку на github) также использовал Serial.print, я предполагаю, что виновником является sprintf.

Известно ли, что sprintf вызывает такие проблемы со временем? Может быть что-нибудь еще?


person eds1999    schedule 12.09.2020    source источник
comment
Разве вы не забываете о нулевом терминаторе при вычислении длины?   -  person JVApen    schedule 12.09.2020
comment
@JVApen, нужен ли в этом контексте нулевой терминатор? sprintf является новым для меня, но поскольку код фактически отправляет то, что я ожидал, через uart, я предположил, что реализовал его правильно. Вы говорите, что msgToSendFormated должен быть на 1 символ больше?   -  person eds1999    schedule 13.09.2020
comment
sprintf напишет это, насколько мне известно, да, это действительно то, что я говорю   -  person JVApen    schedule 13.09.2020
comment
@JVApen, это действительно сработало. Я должен был изучить sprintf немного больше. Большое спасибо!   -  person eds1999    schedule 13.09.2020
comment
Если все, что вы делаете, это отправляете его в Serial, тогда было бы НАМНОГО быстрее и эффективнее использовать несколько операторов Serial.print подряд и отправлять их по частям. Поскольку последовательные данные буферизуются и медленны, фактическая передача будет такой же, получатель никогда не заметит разницы. Это будет больше строк, но намного меньше кода. sprintf — очень дорогая функция.   -  person Delta_G    schedule 13.09.2020
comment
@Delta_G Я понимаю, откуда это взялось, но взгляните на мой исходный код, это именно то, что он делал. С моим новым методом цикл работает в 3 раза быстрее (в среднем он увеличился с 11 Гц до 29 Гц). Если бы не схема (3 символа arg, 15 символов cmd), я предполагаю, что старый метод действительно был бы более эффективным, но мне нужны эти ведущие нули. Приветствуются все предложения, но мне кажется, что sprintf — наиболее эффективный способ добиться этого.   -  person eds1999    schedule 13.09.2020
comment
Ваш исходный код использовал pow. Это была медленная часть. Избавьтесь от этого, и вы сможете сделать этот путь быстрее, чем этот.   -  person Delta_G    schedule 13.09.2020
comment
Почему вы все равно пишете так много символов для cmd. Это инт. Максимум, что может быть, это 5 символов. Таким образом, десять из этих 0 вы можете просто напечатать, не вычисляя ничего. Вы знаете, что в cmd всегда будет не менее 10 нулей.   -  person Delta_G    schedule 13.09.2020
comment
@Delta_G Хм, я посмотрю на это. Причина, по которой я использовал pow, заключалась в том, чтобы упростить параметрическое изменение длины cmd-части сообщения, потому что я знал, что изменю это в будущем. Я знаю, что 15 символов бесполезны, но это временно. Интерпретатору отправляемых сообщений в настоящее время нужны эти 15 символов, но я работаю над этим. (git.io/JU8OU)   -  person eds1999    schedule 13.09.2020


Ответы (1)


Как указал JVApen, sprintf всегда пишет нулевой терминатор. Поскольку длина msgToSendFormated для этого была недостаточной, я бы получил переполнение. Настройка char msgToSendFormated[totalFormatedMsgLength + 1]; устранила проблему.

person eds1999    schedule 12.09.2020