Локальные структуры и память массивов символов не очищаются после возврата функции - PullRequest
0 голосов
/ 07 февраля 2020

У меня есть объявление пары символьных массивов и структур в функции, которая обрабатывает строковое сообщение. Эта функция вызывается периодически, и я заметил, что переменные имеют те же данные, что и при предыдущем вызове функции.

void handle_incoming_message(void)
{
    // All further variables keep previous value 
    message_fields msg_params;
    message_data msg;

    char base_response[16];
    char payload_response[14];
    char tx_msg[50];
    char response_buf[128];

    if(is_valid_msg(&msg, &msg_params) == 1u) // Check if there is message in queue and Checksum is ok
    {
        /* Get all message fields into struct */
        get_msg_fields(&msg_params, &msg); 
     ........

    }
}

И это приводит к ошибке, поэтому, когда я обрабатываю сообщение и пересылаю его, сообщение повреждено, имея некоторые дополнительные данные из предыдущего сообщения (см. рисунок). Первый терминал является исходным сообщением, 2d перенаправлен.

enter image description here

Я также проверил в режиме отладки, и переменные показывают то же значение при следующем вызове, прежде чем они были как-то использованы. (см. рисунок). Данные response_buf, когда функция вызывается 2d раз.

enter image description here

Почему это происходит? Не следует ли очищать локальные переменные после возврата функции? Как правильно обрабатывать такие случаи?

Обновление: добавлена ​​структура Message_fields.

typedef struct message_fields{
    uint8_t sender_id;
    uint32_t payload_fields[NOF_PAYLOAD_FIELDS];
    uint8_t receiver_id;
    uint16_t msg_id;
    uint8_t payload_length;
    char payload_type;
    char payload[128];
    uint8_t checksum;
    uint8_t peripheral_id;
} message_fields;

Ответы [ 2 ]

2 голосов
/ 07 февраля 2020

Локальные переменные, объявленные внутри функции, которые не * явно инициализированы, могут иметь любые значения - и это будет включать значения, оставшиеся после любого предыдущего вызова функции. Как именно ваш конкретный компилятор и система сборки реализуют память для таких переменных, не определено стандартом.

Чтобы избежать проблем, возникающих в результате использования таких неинициализированных данных, добавьте явные инициализаторы в ваш код. Следующее устанавливает все «локальные» данные в нули (вы не дали нам определения для message_fields и message_data, поэтому я даю «возможные» инициализаторы для них):

void handle_incoming_message(void)
{
    // All further variables keep previous value 
    message_fields msg_params = { 0, };
    message_data msg = { 0, };

    char base_response[16] = { 0, };
    char payload_response[14] = { 0, };
    char tx_msg[50] = { 0, };
    char response_buf[128] = { 0, };

    if (is_valid_msg(&msg, &msg_params) == 1u) // Check if there is message in queue and Checksum is ok
    {
        /* Get all message fields into struct */
        get_msg_fields(&msg_params, &msg);
        ........

    }
}
2 голосов
/ 07 февраля 2020

Если локальные переменные не инициализированы явным образом, их значения равны неопределен . Вы не можете зависеть от того, что они имеют какое-то конкретное значение, и на самом деле вы можете вызвать неопределенное поведение , если попытаетесь их прочитать. Как правило, реализации не будут пытаться очистить их при создании. Это одна из вещей, которая делает C быстрой.

Ваш код должен явно инициализировать любые нечитаемые переменные, которые вы читали, с соответствующими значениями по умолчанию, чтобы он действовал детерминистически.

...