Работа с массивами

PoulArty

✩✩✩✩✩✩✩
5 Ноя 2022
14
0
Здравствуйте!
НЕ кидайте тапки сразу, по своей проблеме не смог найти решение на форуме.
История:
На базе ESP8266 разрабатываю устройство.
Его задача по протоколу modbus по serial получить значения от другого промышленного устройства. С подключением и протоколами разобрался. Но стоит задача эти данные и ряд других отправить через mqtt по GSM на сервер, где обработчик все разложит по нужным полкам. И для этого надо значения регистров преобразовать из uint16_t в CHAR и между ними добавить какой либо разделитель. Создана функция, которая получает пять значений регистров с типом uint_16t, каждое значение поочередно добавляет в массив этого же типа и должна его возвращать. Но при вызове функции и обращении к элементам массива в них нет значений. Все меняется, если в функции перед строкой "return <массив>", отправить его значение в терминал по serial.

C++:
uint16_t * readCoils (int registers, int Quanty){
    int j, result;
    uint16_t data[5];

    node.clearResponseBuffer();

    result = node.readCoils(registers, Quanty);
    if (result == node.ku8MBSuccess) {
        for (int i = 0; i < 5; ++i){
            data[i] = (uint16_t)node.getResponseBuffer(i);
        }
    }
    Debug.println(*data); // без этой строки функция возвращает нули
    return data;
}

char * get_char_data_coil(uint16_t *data, int count_data){

    char data_all[80]     =     "";
    char data_1[16]         =  "";
    uint16_t T;
    
    if (node.readCoils(0,1) == node.ku8MBSuccess){
            for (int i = 0; i < count_data; ++i){
                T = (uint16_t)data[i];
                itoa(T, data_1, HEX);
                strcat(data_all, data_1);
                strcat(data_all, "@");
                data_1[0] = 0;
            }
    }
    else{
            strcat(data_all, "NO_COILS");

    }
    Debug.print("coils = "); Debug.println(data_all);
return data_all;
}
Я конечно могу все засунуть в одну функцию, сразу полученное значение одного элемента преобразовать в char и сложить в массив. Но почему так?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
312
100
@PoulArty,
Вы создаете массив внутри функции, и следовательно он локальный и после возврата из функции эта область памяти может перезаписываться другими данными. Если вы не печатаете данные, то компилятор видит, что вы не читаете data до выхода из функции, а значит они вам не нужны и в целях оптимизации, можно ничего в data не писать.
 

PoulArty

✩✩✩✩✩✩✩
5 Ноя 2022
14
0
Извините, но не понимаю. Ведь сама функция создана возвращать данные массива. Я вызываю функцию, что бы она вернула мне свое значение.
В коде это далее вызывается так:
C++:
get_char_data_coil(readCoils(0, 80), 5);
 

poty

★★★★★★✩
19 Фев 2020
2,956
886
@PoulArty,
uint16_t data[5];
выделяет память в стеке. Вы создаёте указатель на эту область памяти и этот указатель правилен только внутри функции. Как только функция завершает свою работу стек становится доступен для следующих применений и может перезаписываться. То есть, такая конструкция не гарантирует, что после выхода из функции кто-то тут же не запишет в эту функцию никаких данных. В каких-то случаях это может сработать, но в общем случае так делать нельзя. Вообще-то компилятор должен был дать warning на такое применение.
 
  • Лойс +1
Реакции: PoulArty

PoulArty

✩✩✩✩✩✩✩
5 Ноя 2022
14
0
Я вызываю функцию get_char_data_coil(uint16_t *data, int count_data),
в этой функции параметром uint16_t *data - является вызов функции readCoils (int registers, int Quanty).
Когда область может перезаписываться?
Уже в функции get_char_data_coil(uint16_t *data, int count_data)?

Как с этим бороться?
 

poty

★★★★★★✩
19 Фев 2020
2,956
886
@PoulArty, нужно представлять как передаются данные в функцию и возвращаются данные из неё. Почитайте хотя бы http://ermak.cs.nstu.ru/trans/Trans461.htm (первое попавшееся). Пропускайте всё, что специфично для контроллера, общий принцип везде один и тот же.
Как с этим бороться?
буфер должен иметь видимость во всех функциях, в которых он используется, если между ними планируется передавать данные. В данном случае это может быть либо глобальная переменная (глобальная область видимости), либо динамически распределённая память (указатель на неё будет валиден всё время жизни буфера, но необходимо следить за своевременным освобождением памяти, иначе столкнётесь с утечкой памяти), либо (относительно рискованный случай) статическая переменная внутри функции (нужно иметь в виду, что её инициализация происходит только при первом входе в функцию).
 
  • Лойс +1
Реакции: PoulArty