Разбор и сравнение строк на Arduino: поведение отличается от gcc?
Я пытаюсь проанализировать простую строку, вывести результат анализа через serial.println и запустить функцию на основе полученной команды. Я написал приведенный ниже код, который прекрасно работает на c (см. приложенный файл c). Однако поведение одного и того же кода в IDE arduino совершенно другое, и я действительно не могу понять, почему.
#include <string.h>
void rcv_msg(char *rcv_msg) {
char *all_tokens[2];
int i = 0;
all_tokens[i] = strtok(rcv_msg, "{,}");
while (all_tokens[i] != NULL) {
all_tokens[++i] = strtok(NULL, "{,}");
}
char *command = all_tokens[0];
char *value = all_tokens[1];
/*
//Эти принтлы не работают, они игнорируются, почему?
Serial.println("all_tokens[0]: ");
Serial.println(all_tokens[0]);
Serial.println("all_tokens[1]: ");
Serial.println(all_tokens[1]);
*/
if (strcmp(command,"message_1") == 0 && strcmp(value,"1") == 0) {
Serial.println("message 1: ");
Serial.println(command);
Serial.println(value);
Serial.println(" ");
}
if (strcmp(command,"message_2") == 0 && strcmp(value,"0") == 0) {
Serial.println("message 2: ");
Serial.println(command);
Serial.println(value);
Serial.println(" ");
}
}
void setup() {
Serial.begin(115200);
}
void loop() {
char msg1[] = "{message_1,1}";
char msg2[] = "{message_2,0}";
Serial.println("Send msg1: ");
rcv_msg(msg1);
delay(5000);
Serial.println("Send msg2: ");
rcv_msg(msg2);
delay(5000);
}
Этот код выводит на последовательный монитор следующий неверный вывод:
Отправить сообщение 2: сообщение 2: сообщение_2 {сообщение_2,0}
Отправить сообщение 1: сообщение 2: сообщение_1 {сообщение_2,0}
Отправить сообщение 2: сообщение 2: сообщение_2 {сообщение_2,0}
Отправить сообщение 1: сообщение 2: сообщение_1 {сообщение_2,0}
Во-первых, я не понимаю, почему в начале сообщение 2 печатается перед сообщением 1, хотя сообщение 1 было отправлено первым. Во-вторых, мне непонятно, что сравнение, выполненное с помощью strcmp, всегда возвращает сообщение 2.
Что еще более важно, почему запуск того же кода в c дает правильный вывод? Интересно, есть ли какая-либо ошибка в моем коде Arduino. Кстати, я тестирую код на Teensy 3.2, но планирую использовать его и на Arduino Uno.
Код c (идеально работающий):
#include <string.h>
#include <stdio.h>
void rcv_msg(char *rcv_msg) {
char *all_tokens[2]; //ПРИМЕЧАНИЕ: сообщение состоит из двух токенов: команда и значение
int i = 0;
all_tokens[i] = strtok(rcv_msg, "{, }");
while (all_tokens[i] != NULL) {
all_tokens[++i] = strtok(NULL, "{, }");
}
printf("all_tokens[0] : %s \n", all_tokens[0]);
printf("all_tokens[1] : %s \n", all_tokens[1]);
char *command = all_tokens[0];
char *value = all_tokens[1];
printf("command : %s \n", command);
printf("value : %s \n", value);
if (strcmp(command,"message_1") == 0 && strcmp(value,"1") == 0) {
printf("activating command : %s %s \n\n\n", command, value);
}
if (strcmp(command,"message_2") == 0 && strcmp(value,"0") == 0) {
printf("activating command : %s %s \n\n\n", command, value);
}
}
int main() {
char msg1[] = "{message_1, 1}";
char msg2[] = "{message_2, 0}";
rcv_msg(msg1);
rcv_msg(msg2);
}
@L_T, 👍1
1 ответ
Лучший ответ:
Обе версии вашего кода имеют неопределенное поведение. На данном входе ваш код вызовет strtok
три раза и сохранит результат в массиве три раза: для первого токена, для второго token и, наконец, для нулевого указателя. Вы сохраняете все три (включая этот нулевой указатель!) в массиве all_tokens
, который имеет размер 2
.
Вы, очевидно, знаете о потенциальной опасности переполнения массива: вы даже написали этот комментарий в своем коде
char *all_tokens[2]; //ПРИМЕЧАНИЕ: сообщение состоит из двух токенов: команда и значение
и еще в следующем цикле
int i = 0;
all_tokens[i] = strtok(rcv_msg, "{, }");
while (all_tokens[i] != NULL) {
all_tokens[++i] = strtok(NULL, "{, }");
}
вы по-прежнему настаиваете на хранении более двух значений в массиве all_tokens
.
Кроме того, во второй версии вашего кода используются совершенно другие значения ключей сообщений (почему это вдруг "motor1_pattern1"
вместо "message_1"
?), что делает его непонятно, как вы сравнили функционал второй версии с функционалом первой.
- Чтение изображений bmp с SD-карты, преобразование их и отображение на последовательном мониторе в Arduino
- Что может вызвать задержку при использовании последовательного порта между Arduino IDE и внешними клиентами?
- C++ против языка Arduino?
- avrdude ser_open() can't set com-state
- Как читать и записывать EEPROM в ESP8266
- Float печатается только 2 десятичных знака после запятой
- устаревшее преобразование из строковой константы в 'char*'
- Запрограммировать ATMega328P и использовать его без платы Arduino.
большое спасибо. Я добавил while (i < 2 && all_tokens != NULL), что решило проблему. Это лучший способ сделать это? Также я отредактировал код, удалив motor1_pattern с message_1 (извините, я сделал неудачную копию-вставку). Я все еще удивляюсь: Почему серийный монитор по-прежнему отображает сначала второе сообщение, хотя первое сообщение было отправлено. Кажется, первое сообщение не доходит до серийного монитора... что я упускаю? Наконец, вы предлагаете использовать strtok_r вместо strtok?, @L_T
Предлагаю посмотреть на сообщение об использовании памяти при компиляции. Arduino имеет лишь небольшой объем оперативной памяти, а строковые функции используют много. Если ваш код очень маленький, он может работать, но чем больше вы будете увеличивать размер кода, тем более странными будут результаты., @Peter