Показано с 1 по 9 из 9

Тема: Разыменование неверного указателя

  1. #1

    По умолчанию Разыменование неверного указателя

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

  2. #2

  3. #3

    По умолчанию

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

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

  4. #4
    Супер Модератор Аватар для Евгений Кислов
    Регистрация
    27.01.2015
    Адрес
    Москва
    Сообщений
    12,032

    По умолчанию

    Ошибка на 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 элемента, просто увидите ли вы их или нет - зависит от того, как именно распределилась память при очередной компиляции.

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

    2023-03-06_7-09-03.png

  5. #5

    По умолчанию

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

  6. #6
    Супер Модератор Аватар для Евгений Кислов
    Регистрация
    27.01.2015
    Адрес
    Москва
    Сообщений
    12,032

    По умолчанию

    Цитата Сообщение от Paha1977 Посмотреть сообщение
    Спасибо большое. Теперь понятно. Массив указателей никак не привязывается к индексам массива, на который ссылается.
    А можно каким-либо образом сделать, чтобы ptCol[28] указывал на GVL.astCol_5[28], а ptCol[49] - на GVL.astCol_8[49]?
    Через ARRAY [..] OF POINTER TO circuit.
    Но, на мой взгляд, это выглядит довольно сомнительным решением.
    Впрочем, саму задачу вы так и не описали, так что сложно о чем-то рассуждать.

  7. #7

    По умолчанию

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

  8. #8
    Супер Модератор Аватар для Евгений Кислов
    Регистрация
    27.01.2015
    Адрес
    Москва
    Сообщений
    12,032

    По умолчанию

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

  9. #9

    По умолчанию

    Цитата Сообщение от Евгений Кислов Посмотреть сообщение
    Через 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 и различаются они только количеством и порядковыми номерами устройств, а алгоритмы для каждого одинаковы, есть желание задуматься об удобстве и унификации.
    Последний раз редактировалось Paha1977; 06.03.2023 в 20:02.

Похожие темы

  1. Как записать по адресу указателя?
    от Загнетов в разделе ПЛК1хх
    Ответов: 26
    Последнее сообщение: 12.01.2024, 04:34
  2. Инициализация указателя
    от drvlas в разделе ПЛК1хх
    Ответов: 17
    Последнее сообщение: 07.06.2016, 19:28
  3. Ответов: 29
    Последнее сообщение: 20.02.2012, 06:44

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •