PDA

Просмотр полной версии : ADR(%X.X) в указатель неверного типа — бип-бип и стоп



Yegor
13.02.2012, 11:13
Если сделать вот так...

VAR
pointer: POINTER TO INT;
integer: INT;
END_VAR

pointer := ADR(%IB1.0);
integer := pointer^;... то ПЛК160 начинает лихорадить: он проглатывает программу, но при её запуске пару секунд думает, издаёт сигнал и останавливается. КДС при этом теряет соединение и разлогинивается. При повторных попытках КДС перед заливкой проги сообщает об отсутствии программы на контроллере. Стоит переделать тип указателя на BYTE, как всё встаёт на свои места. А странно здесь то, что Codesys не знает размер %IB1.0 и не сообщает об ошибке в программе.

Александр Приходько
13.02.2012, 11:45
Предполагаю, что проблема в типе данных. Попробуйте поставить тип Byte. А вы обращаетесь к большему числу данных.

capzap
13.02.2012, 13:07
либо
pointer := ADR(BYTE_TO_INT(%IB1.0)); должно несколько разрядить обстановку, правда сам не пробовал

lara197a
13.02.2012, 21:16
Я в свое время разбирался с этим вопросом, консультировался у И. Петрова. Давно, года 4 назад.
Не помню точно, то ли в этой платформе, то ли в этом контроллере, но битовая адресация по указателю не работает.
BYTE используйте.

capzap
13.02.2012, 21:25
у битовых переменных свои команды, это прописано и в codesys_v23_ru.pdf. В вопросе изачально стоит байт, а указатель на два байта, отсюда и вся "котовасия", её можно решить явным преобразованием или в конфигураторе присвоить требуемому байту имя и с ним уже работать в программе

lara197a
13.02.2012, 21:49
Не, то же не работают.
Я когда с указателями в целом разбирался, то столкнулся с тем, что команды есть, а выполнения нет. Обращался в Пролог.

capzap
13.02.2012, 22:13
однозначно POINTER TO работает с байтами и выше, что же касается BITADR то его значение, чем то схоже с указателями из сименса, младшие три разряда отведены под биты, остальное зависит от установленных свойств, либо сразу номер по порядку байта, либо через разряд

lara197a
13.02.2012, 22:17
Я и говорю, что с BYTE работает.

Yegor
14.02.2012, 10:12
Честь и хвала КДС что он при работе с указателями разрешает юзеру брать всю ответственость на себя а не считает юзера априори дебилом.Как-то непоследовательно получается. Где тогда сишные «булевые»? Где работа с указателем-результатом функции без временных переменных? Хочу GetPointer()^.DoSomething(), а нельзя.

capzap
14.02.2012, 11:39
это Вы сейчас с кем разговаривали и на каком языке? :)
Вам вроде все подсказали как поступить в приведенном в первом посте случае. Опишите следующую задачу, так же поможем. С командой BITADR можно читать булевы значения, только записать невозможно без созданния дополнительного блока

Yegor
14.02.2012, 13:40
в сиЭто многое объясняет, спасибо.
А верните само значение из функции, зачем плодить лишний код ?Смысл GetPointer()^.DoSomething() как раз в сокращении кода. Тип возврата функции компилятору известен.

На мой взгляд в языке со строгой типизацией для критически важных объектов фокусы вроде попытки прочитать INT вместо BYTE должны пресекаться на ранних этапах.

swerder
14.02.2012, 17:06
На мой взгляд в языке со строгой типизацией для критически важных объектов фокусы вроде попытки прочитать INT вместо BYTE должны пресекаться на ранних этапах.

хотите, чтоб кдс вам по рукам скалкой бил?)

Yegor
15.02.2012, 05:21
Хочу, чтобы спрашивал у меня и не выдумывал, если что-то непонятно.

capzap
15.02.2012, 05:31
а ПЛК ничего и не выдумывал, ему сказали создать ссылку на 2-х байтовоую переменную, он создал. Запросили результат начиня с адреса однобайтовой переменной, он и выдал результат из памяти в размере 2-х байт. Всё сделал строго по инструкции, полученной от программиста.
:) Поговорка про таких как Вы есть: "Не чего на зеркало пенять, коль ..."

Yegor
15.02.2012, 10:49
а ПЛК ничего и не выдумывалА к ПЛК претензий и не было.

Указатели типизированные. Где type mismatch при попытке присваивания без явного приведения?

Yegor
15.02.2012, 10:56
На этой ноте стоит, наверное, закругляться. Тут уже вопросы к разработчикам кодесиса.

capzap
15.02.2012, 11:18
А к ПЛК претензий и не было.

Указатели типизированные. Где type mismatch при попытке присваивания без явного приведения?

То что Вы привели в начале, там везде явные типы, вот Валенок показал не явное.

Yegor
15.02.2012, 11:56
type mismatch ? пжста

p : pointer to int;

P^ := 3.3;p^ это уже ссылка (разыменованный указатель), а не указатель. Вы делаете int := real. Указатель в указатель это вот так:

pi: POINTER TO INT;
pr: POINTER TO REAL;
pi := pr; (* Компилятор молча компилирует *)

capzap
15.02.2012, 12:56
Вы до сих пор не "въехали" в концепцию программирования контроллеров. В этом примере не на что ругаться, указателю pi дали команду считать два байта с началом адресации указателя на реал. если pr:=ADR(value), где value = 25,5, то pi в Вашем случае будет равно нулю. Таким образом можно раскладывать числа REAL в регистры модбаса, этим ни кто не пользуется потому что есть более легкие и короткие способы. Так что ругатся тут компилятору не на что



pi:POINTER TO INT;
pr:POINTER TO REAL;
ril:REAL:=36.6; (*25.5*)
ine:INT;
ine1:INT;
//**********
pr:=ADR(ril);
pi:=pr;
ine:=pi^;
pi:=pi+2;
ine1:=pi^;здесь pi:=pi+2; смещение указателя на два байта

Yegor
15.02.2012, 13:15
Даже в C++, где есть сотни способов выстрелить себе в ногу, компилятор не сделает за вас из указателя одного типа указатель другого, хоть этому ничто и не препятствует с технической точки зрения. При этом можете сделать reinterpret_cast, и тогда плюсовый компилятор всё съест подобно кодесисовскому. Отличие-то в том, что вы явно указываете своё намерение произвести такую манипуляцию.

Молчание компилятора в этом случае опасно. Например, если у вас есть функция, которая возвращает указатель определённого типа, то вы можете изменить тип этого указателя в определении функции, но забыть учесть это изменение там, где функция вызывается. А компилятор ничего не скажет. Я против такого поведения.

capzap
15.02.2012, 13:55
Вам срочно нужно абстрагироваться от сишного программирования, в КДС указатели имеют отношение к областям памяти выраженной в байтах, к типам они привязаны только одним местом, это количеством байт. Как раз основная работа в КДС и заключается, чтоб с помощью указателей из типа большей емкости взять только часть и к примеру поменять местами для отправки по каналу связи двух регистров модбаса. Поэтому Ваше предложение информировать о таких не соответствиях меня бы стало сильно раздражать при работе с проектом

Yegor
16.02.2012, 06:05
Ровно то - что я написал
p : pointer to int;
P^ := 3.3;Повторюсь: выражение p^ не является указателем. КДС молча пройдёт через pointer_to_book := pointer_to_dog.
Пока я в КДС мне абсолютно побоку что там в с++, в котором указатели нужно перекладывать через нетипизированные или там делать reinterpret_cast. Ой-ой, а ведь так хотелось сократить код используя GetPointer()^.DoSomething()Второе это отдельная проблема, не относящаяся к контролю типов указателей.
Вам срочно нужно абстрагироваться от сишного программирования, в КДС указатели имеют отношение к областям памяти выраженной в байтах, к типам они привязаны только одним местом, это количеством байт. Как раз основная работа в КДС и заключается, чтоб с помощью указателей из типа большей емкости взять только часть и к примеру поменять местами для отправки по каналу связи двух регистров модбаса. Поэтому Ваше предложение информировать о таких не соответствиях меня бы стало сильно раздражать при работе с проектом... и сюда же...
Вы пришли в эту столовую, и о ужос - тут есть вилки, а ими можно выколоть себе глаз, и начинаете требовать чтоб их убрали.Когда вы делаете, скажем, DWORD_TO_INT, вас это сильно раздражает? Или кому-то обязательность таких преобразований кажется глупым запретом на вилки?

capzap
16.02.2012, 08:29
DWORD_TO_INT, вас это сильно раздражает?
Нет, такое чуство ко мне не приходит, точно так же когда я пальчиками давлю на клавиатуру, я понимаю, что у меня указатель определенного типа и предложить ему переменную, я должен того же типа и если не помню какого, то перевожу взгляд в окно объявлений и смотрю на тип указателя

Yegor
16.02.2012, 10:11
Нет, такое чуство ко мне не приходитНе приходило бы и при явном приведении с указателями.
я понимаю, что у меня указатель определенного типа и предложить ему переменную, я должен того же типа и если не помню какогоВ реальности помимо «помню-не помню» есть ещё «ошибаюсь». Потому и запрещено неявное преобразование DWORD в INT. А вот с указателями почему-то всё дозволено.

capzap
16.02.2012, 10:51
Если я делаю DWORD_TO_INT, то получаю только младшие байты, если я использую указатель то по моему желанию я могу из DWORD-а получить два старших байта для превращения их в INT, что не получится используя первую команду. Я сознательно иду на такой шаг и меня будет раздражать, когда компилятор меня будет информировать, что я не правильно поступаю.

Yegor
16.02.2012, 11:21
Он не будет информировать, т.к. в этом случае вы воспользуетесь явным преобразованием вроде DWORD_TO_INT, только для указателей.

capzap
16.02.2012, 12:28
Например, если у вас есть функция, которая возвращает указатель определённого типа, то вы можете изменить тип этого указателя в определении функции, но забыть учесть это изменение там, где функция вызывается.
создал функцию
FUNCTION crash : POINTER TO DWORD
VAR_INPUT
uno : DWORD;
END_VAR

//***********
crash:=ADR(uno);
crash:=crash+2;
в программе записал следующее
duo:=crash(uno);
x:=duo^;затем сменил crash : POINTER TO INT, результат выполнения тот же.

Yegor
17.02.2012, 05:06
Повторюсь тоже. Хотели несоответствие типов – получили.Как бы ещё-то сказать... Где в вашем примере присваивание указателя одного типа в переменную-указатель другого?
Вы хоть читали устав местного монастыря ? Там четко и ясно : указатели – вне МЭК.Я где-то ссылался на стандарт? Да пускай хоть за три версты от него — единообразие всё равно должно быть.
Давайте пойдем дальшеВы понеслись сломя голову, а не пошли.
затем сменил crash : POINTER TO INT, результат выполнения тот же.Потому что памяти по-прежнему выделяется для DWORD. Кстати, в долгосрочной перспективе полученный указатель опасен, т.к. ссылается на освобождённый участок памяти (время жизни переменной uno).

capzap
17.02.2012, 07:54
Потому что памяти по-прежнему выделяется для DWORD. Кстати, в долгосрочной перспективе полученный указатель опасен, т.к. ссылается на освобождённый участок памяти (время жизни переменной uno).Как бы тоже объяснить, я сменил не во время работы ПЛК, а остановив процесс, отрдактировав проект, загрузив по новой и память должна распределится уже исходя из новых условий, то что у меня удачно получилось именно в данном случае, этим я хотел показать что бывают моменты, когда компилятору не стоит выдавать сообщений потому что я знаю что делаю.


Где в вашем примере присваивание указателя одного типа в переменную-указатель другогоУказатель показывает адрес памяти с какого байта нужно собирать информацию, а количество взятых байт зависит от типа указателя, не вижу смысла в Ваших словах указателю присвоить указатель, это масло масленное, если мне необходимо второму указателю что то и присвоить, я опять обращусь к команде ADR(что_то_там), точно так же как я это сделал с первым указателем, и если даже второй указатель другого типа, он возьмет свое определенное количество информации в байтах

Yegor
20.02.2012, 05:44
А что такое указатель ?p — указатель, p^ — не указатель

Ладно, хватит. Ваша взяла. С указателями всё чики-пуки и ваще кодесис лапочька там всё ок.