PDA

Просмотр полной версии : Разыменование неверного указателя



Paha1977
05.03.2023, 19:31
Добрый вечер
Сломал мозк уже!
Есть две структуры - простая и retain. Они упакованы в 4 массива.
Есть два массива указателей, к которым привязаны эти 4 массива. Изобразил на картинке:
66332
Суть проблемы: при доступе к массиву указателей, начиная с выделенных красным элементов массива теряются указатели.
66333
Куда копать дальше - не знаю. Помогите, пожалуйста.

Евгений Кислов
05.03.2023, 19:47
Добрый день.
Выложите простейший проект, в котором воспроизводится эта проблема.

Paha1977
05.03.2023, 20:39
Вот, вроде получилось.
66334
Ошибка на 54 элементе.
https://disk.yandex.ru/d/j7fo2vP69UPP2g

Добавлю, что в эмуляторе и виртуальном ПЛК все работает норм.

Евгений Кислов
06.03.2023, 07:14
Ошибка на 54 элементе.

Гораздо раньше.


Добавлю, что в эмуляторе и виртуальном ПЛК все работает норм.

Вы ошибаетесь. Просто из-за другого распределения памяти ошибка там не так явно видна.

Заключается она в следующем.

1. Тут вы обещаете компилятору, что на входы ptCol и ptrCol будут переданы адреса массивов, каждый из которых содержит 27 элементов:



ptCol :POINTER TO ARRAY [28..54] OF circuit; //указатели на массив данных коллекторов
ptrCol :POINTER TO ARRAY [28..54] OF circuit_ret; //указатели на массив retain данных коллекторов

2. Но фактически в вызове вы передаете адреса массивов, содержащие 6 элементов.



astCol_8 :ARRAY [49..54] OF circuit;
astrCol_8 :ARRAY [49..54] OF circuit_ret;


POU(
ptCol:= ADR(GVL.astCol_8),
ptrCol:= ADR(GVL.astrCol_8),
uiEnumStart:= 49,
uiEnumEnd:= 54,
uiStartStep:= uiStep
);


Что происходит в результате:

ptCol[28] указывает на GVL.astCol_8[49]
ptCol[29] указывает на GVL.astCol_8[50]
...
ptCol[33] указывает на GVL.astCol_8[54]

Аналогично с ptrCol.

ptCol[34] / ptrCol[34] и далее указывают куда-то - в область памяти приложения, где хранятся какие-то другие данные.
"Разыменование неверного указателя" - это когда вы "смотрите" по указателю на ячейку, где ожидаете BOOL (т.е. байт памяти со значение 0 или 1), а там хранится какое-то другое число (например, 123).

Теперь вы спросите, почему проблемы только с 52-54 элементом.
На самом деле, проблемы, как я уже сказал, начинаются с 34 элемента, просто увидите ли вы их или нет - зависит от того, как именно распределилась память при очередной компиляции.

Открыв ваш проект, я выполнил полную перекомпиляцию, и после этого гораздо более отчетливо видно, в какой момент начинаются проблемы:

66338

Paha1977
06.03.2023, 17:12
Спасибо большое. Теперь понятно. Массив указателей никак не привязывается к индексам массива, на который ссылается.
А можно каким-либо образом сделать, чтобы ptCol[28] указывал на GVL.astCol_5[28], а ptCol[49] - на GVL.astCol_8[49]?

Евгений Кислов
06.03.2023, 17:17
Спасибо большое. Теперь понятно. Массив указателей никак не привязывается к индексам массива, на который ссылается.
А можно каким-либо образом сделать, чтобы ptCol[28] указывал на GVL.astCol_5[28], а ptCol[49] - на GVL.astCol_8[49]?

Через ARRAY [..] OF POINTER TO circuit.
Но, на мой взгляд, это выглядит довольно сомнительным решением.
Впрочем, саму задачу вы так и не описали, так что сложно о чем-то рассуждать.

Paha1977
06.03.2023, 17:48
Задача довольна проста. Обработка массивов структур с индексами, которые идут не от нулевого значения. Каждый индекс структуры равен номеру физической установки, что в дальнейшем облегчает отладку и мониторинг. Обработка каждой установки происходит в подпрограмме, где все установки загнаны в цикл FOR, так как они все одинаковые. Подпрограмме передается начальный и конечный индексы установок, а также указатели на соответсвующие массивы структур.

Евгений Кислов
06.03.2023, 18:00
Задача довольна проста. Обработка массивов структур с индексами, которые идут не от нулевого значения. Каждый индекс структуры равен номеру физической установки, что в дальнейшем облегчает отладку и мониторинг. Обработка каждой установки происходит в подпрограмме, где все установки загнаны в цикл FOR, так как они все одинаковые. Подпрограмме передается начальный и конечный индексы установок, а также указатели на соответсвующие массивы структур.

Это не задача. Это выбранное вами решение.
Но, в любом случае, не проще ли в структуру добавить поле с "номером физической установки", и сделать прозрачную нумерацию массивов? (с 0 или 1)
На мой взгляд, это предотвратило бы допущенную вами ошибку (или, по крайней мере, позволило довольно быстро бы ее осознать).

Paha1977
06.03.2023, 18:50
Через ARRAY [..] OF POINTER TO circuit.
Спасибо за подсказку. Так работает.


PROGRAM PLC_PRG
VAR
iNC :INT; //номер контура
iSD :INT; //номер элемента массива в SlaveData

ptCol :ARRAY [28..54] OF POINTER TO circuit;
ptrCol :ARRAY [28..54] OF POINTER TO circuit_ret;

astCol_5 :ARRAY [28..37] OF circuit;
astCol_8 :ARRAY [49..54] OF circuit;

stSlaveData: slave_data;
END_VAR

VAR RETAIN
astrCol_5 :ARRAY [28..37] OF circuit_ret;
astrCol_8 :ARRAY [49..54] OF circuit_ret;
END_VAR

iSD:=0;
FOR iNC:=28 TO 37 DO
ptCol[iNC]:= ADR(astCol_5[iNC]);
ptrCol[iNC]:= ADR(astrCol_5[iNC]);
PLC_PRG.CONTR_CIRC();
END_FOR

FOR iNC:=49 TO 54 DO
ptCol[iNC]:= ADR(astCol_8[iNC]);
ptrCol[iNC]:= ADR(astrCol_8[iNC]);
PLC_PRG.CONTR_CIRC();
END_FOR

Разыменование теперь, естественно, выглядит иначе.


rInput:=ptCol[iNC]^.rOutInPercent


Это не задача. Это выбранное вами решение.
Но, в любом случае, не проще ли в структуру добавить поле с "номером физической установки", и сделать прозрачную нумерацию массивов? (с 0 или 1)
Согласен, когда речь идет о разовом проекте. Когда таких шкафов более 60 и различаются они только количеством и порядковыми номерами устройств, а алгоритмы для каждого одинаковы, есть желание задуматься об удобстве и унификации.