Страница 1 из 4 123 ... ПоследняяПоследняя
Показано с 1 по 10 из 35

Тема: POINTER TO what?

  1. #1
    Пользователь Аватар для drvlas
    Регистрация
    30.09.2010
    Адрес
    Киев
    Сообщений
    700

    По умолчанию POINTER TO what?

    ВНИМАНИЕ: тема рассмотрена с многочисленными заблуждениями и отклонениями. Можешь посмотреть на 4 страницу, там резюме. Читать все подряд позволено только совершеннолетним

    Пробую использовать указатели на переменные. В принципе, получается. Но удивляет (а значит, может когда-то подставить "подножку") такая вольность: я могу сделать

    POINTER TO INT
    или
    POINTER TO DINT

    - а ничегошеньки не изменится. Это и понятно: ведь сказано, что, цитирую

    Обратите внимание: Указатели инкрементируются побайтно! Для увеличения указателя, как это принято в C-
    компиляторах, используйте инструкцию p=p+SIZEOF(p^);

    Из этого следует, что никакой разницы в том, объявили ли мы указатель на 1-байтную переменную или на 4-хбайтную - нет. Он сам по себе укажет адрес (первого байта) переменной и при выполнении операции инкремента будет смещаться на один байт всегда.

    Тогда вопрос: почему же так странно сделано? Вроде как лишнее вот это самое

    TO INT
    TO DINT

    сказали POINTER - и все дела...
    Последний раз редактировалось drvlas; 04.12.2010 в 23:49.

  2. #2
    Пользователь Аватар для drvlas
    Регистрация
    30.09.2010
    Адрес
    Киев
    Сообщений
    700

    По умолчанию в догонку - Word и Uint

    уважаемые знатоки,

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

    итак, есть типы данных

    Word и Uint
    Dword и Udint

    из описания в кодесис, а также из известной книги товарища петрова я вижу, что использовать (d)word можно всегда, когда используется U(d)int, но не наоборот. разница, если я правильно понял, в том, что с (d)word можно выполнять битовые операции, а с U(d)int - нельзя.

    означает ли это, что использование U(d)int - исключительно дело вкуса программиста? или, иначе говоря, если у меня со вкусом все "параллельно", то я могу просто забыть о существовании типов U(d)int - и никогда не пострадаю?

    спасибо!

  3. #3
    Пользователь
    Регистрация
    23.09.2008
    Адрес
    Центророссийск
    Сообщений
    2,318

    По умолчанию

    1.В паскале есть нетипизированный указатель. Просто pointer.
    Он нужон, если я не запамятовал, как буфер для жонглирования типизироваными указателями.
    В племянике паскаля (st) указатели можно перекидывать без буфера, а для работы с заранее неопределенным типом можно использовать dword, по этому "просто поинтер" не нужен.

    По поводу указателя на тип.

    W : word := 345;
    B : byte;
    StartMotor : bool := FALSE; (* Михалыч сказал не трогать на время отладки *)
    pW : pointer to word;
    --------------------------------------
    pW := adr(B);
    pW^ := W;

    Угадайте, сколько будет в B ? Некоторые могут сказать что 89. Наверное. Но Михалыч может сказать вам : Ё.. мать !! Студент бип-бип-бип !!!! Я же сказал тебе – НЕ ВКЛЮЧАТЬ !!.

    2. Если отбросить словесную шелуху, то использование uint или word – по барабану, при условии что вы четко понимаете как они работают на уровне битов.
    Последний раз редактировалось Валенок; 30.11.2010 в 20:53.

  4. #4

    По умолчанию

    Цитата Сообщение от валенок Посмотреть сообщение
    ...
    угадайте, сколько будет в B ? некоторые могут сказать что 89. наверное. ...
    поменьше загадок, с овеном их и так хватает!

  5. #5
    Пользователь
    Регистрация
    23.09.2008
    Адрес
    Центророссийск
    Сообщений
    2,318

    По умолчанию

    Если наберется достаточная группа для кого это - загадка,
    прочитаю лекцию.Небезвозмездно.Дитям на д.Мороза надоть.

    PS
    Овен тут не причем.

  6. #6

    По умолчанию

    Валенок -респект и уважение. Пример работы с указателями - просто зачет. Классическая ошибка даже для опытного программиста.
    Бесплатное разъяснение. st - не java и не .net. Он не сечет неправильной работы с областями памяти.
    Если мы пересылаем в b(byte) двухбайтовое по указателю то записывется и переменная старт_мотор. В результате студент от Михалыча получает по шее.

  7. #7
    Пользователь Аватар для drvlas
    Регистрация
    30.09.2010
    Адрес
    Киев
    Сообщений
    700

    По умолчанию

    Пробую осмыслить заковыристый стиль уважаемого Учителя. Начнем с простого:
    Цитата Сообщение от Валенок Посмотреть сообщение
    2. Если отбросить словесную шелуху, то использование uint или word – по барабану, при условии что вы четко понимаете как они работают на уровне битов.
    Ну непонятна мне фраза "если вы четко понимаете". Насколько четко?

    На уровне размещения в памяти побайтно - трудно вообразить, что для uint и word используется разные правила. Значит, думаем. что старший байт uint и старший байт word будут лежать одинаково. Так?
    Побитно - дык, в байте уж никак не развернут наоборот.
    Что еще нужно понимать, чтобы забыть вообще про существование типа uint?
    Вопрос даже не в практической плоскости, а в понимании "странности" стандарта.

    Теперь к главному.
    Цитата Сообщение от Валенок Посмотреть сообщение
    для работы с заранее неопределенным типом можно использовать dword, по этому "просто поинтер" не нужен.
    Похоже, что есть разница, что использовать. Я провел эксперименты, запутался безнадежно, потом сузил поле до 2-х типов: WORD и DWORD. И что получилось.

    Готовим несколько переменных типа WORD и DWORD, причем из W и DW будем только черпать инфо, их не изменяем. А для измены есть переменные с цифрами 1...4.
    Также есть по 2 указателя, одна пара будет использоваться для указание на источник данных, другая - на приемник.

    Код:
    VAR
    	DW:	DWORD := 16#10104;
    	DW1:	DWORD;
    	DW2:	DWORD;
    	DW3:	DWORD;
    	DW4:	DWORD;
    	pDWsour:	POINTER TO DWORD;
    	pDWdest:	POINTER TO DWORD;
    	W:	 	WORD := 16#102;
    	W1:	WORD;
    	W2:	WORD;
    	W3:	WORD;
    	W4:	WORD;
    	pWsour:	POINTER TO WORD;
    	pWdest:	POINTER TO WORD;
    END_VAR
    В программе 4 шага. В каждом из них рассматриваетм передачу данных, указываемых пойнтерами, в ячейки, адресуемые тоже через указатели. При этом каждый из шагов отличается тем, что присвоение указателям значений (адресов ячеек) производтся с "вывихами":

    Код:
    pDWsour	 := ADR(DW);		(* Source is right *)
    pWsour	 := ADR(W);
    pDWdest	 := ADR(DW1);		(* Destin is right *)
    pWdest	 := ADR(W1);
    pDWdest^	:= pDWsour^ +1;	(* DW <= DW *)
    pWdest^	:= pWsour^ +1; 	(* W <= W *)
    
    pDWsour	:= ADR(W);		(* Source is wrong *)
    pWsour 	:= ADR(DW);
    pDWdest	 := ADR(DW2);		(* Destin is right *)
    pWdest	 := ADR(W2);
    pDWdest^	:= pDWsour^ +1;	(* DW <= W, fetch throu pDW *)
    pWdest^	:= pWsour^ +1; 	(* W <= DW, fetch throu pW *)
    
    pDWsour	 := ADR(DW);		(* Source is right *)
    pWsour	 := ADR(W);
    pWdest	 := ADR(DW3);		(* Destin is wrong *)
    pDWdest	 := ADR(W3);
    pDWdest^	:= pDWsour^ +1;	(* W <= DW, written throu pDW *)
    pWdest^	:= pWsour^ +1; 	(* DW <= W, written throu pW *)
    
    pDWsour	:= ADR(W);		(* Source is wrong *)
    pWsour 	:= ADR(DW);
    pWdest	 := ADR(DW4);		(* Destin is wrong *)
    pDWdest	 := ADR(W4);
    pDWdest^	:= pDWsour^ +1;	(* W <= W  throu pDW *)
    pWdest^	:= pWsour^ +1; 	(* DW <= DW  throu pW *)
    Результаты таковы. Во-первых, компилятор не ругается. Хотя, когда я пробовал приемник данных указывать явно - требовал иногда преобразования типов.

    А дальше вот что. При правильном использовании пойнтеров все хорошо, но это ясно. В остальных случаях некоторые присвоения правильны, некоторые нет. Более того, выполнение последнего оператора (передача двойного слова через 2 пойнтера на слово) - прерывает исполнение программы

    Доступ по несуществующему адресу. ПЛК остановлен

    (Слава Богу, что мы не управляли котельней!)

    Грустный вывод. Хоть компилятор и пропустит, но жизнь поправит. Причем, уважаемый Учитель, хочу заметить, что даже при использовании указателя высшего типа на (шаге 2)

    pDWdest^ := pDWsour^ +1; (* DW <= W, fetch throu pDW *)

    результат неверен
    Т.е., использование DWORD при выборке из переменной типа WORD "прихватывает" еще несколько байт и пихает их в приемник (в нашем случае это приемник типа DWORD, поэтому мы и увидели всеь ужас прихватки).

    Не знаю, наскольок мои путанные мысли что-то продвинули, но теперь думаю, что придется все переменные, на которые буду указывать DWORD-пойнтером, искусственно повышать до типа DWORD. А там еще и переменные TIME есть... Пойду удавлюсь.

  8. #8
    Пользователь
    Регистрация
    23.09.2008
    Адрес
    Центророссийск
    Сообщений
    2,318

    По умолчанию

    Начнем с простого:
    ... Пойду удавлюсь.
    Когда лопнет веревка, открываем литературу по ЛЮБЫМ языкам программирования, и изучаем типы, типытипы(и особенно - их размеры)
    Не забываем что pointer - сам по себе тоже тип.

    А pointer to что-то :

    1.Директива компилятору - как использовать бессмысленный набор байтов по указанному адресу.
    2.Вытекает из 1. и (ВНИМАНИЕ !) какое кол-во этих байтов


    Ошибка 1. (Толстая)
    pDWsour := ADR(W); (* Source is wrong *)
    ...
    pDWdest := ADR(DW2); (* Destin is right *)
    ...
    pDWdest^ := pDWsour^ +1; (* DW <= W, fetch throu pDW *)
    pDWdest^:= word_to_dword( dword_to_word( pDWsour^)) +1;
    (word_to_dword конечно же избыточен,но показывает ход преобразований)
    или проще
    := ( pDWsour^ and 16#0000_FFFF ) + 1;


    Ошибка 2. (Тоньше 1.)

    VAR
    ......
    W4: WORD;
    pWsour: POINTER TO WORD;

    pWdest: POINTER TO WORD;
    END_VAR

    pDWsour := ADR(W); (* Source is wrong *)
    pWsour := ADR(DW);
    pWdest := ADR(DW4); (* Destin is wrong *)
    pDWdest := ADR(W4);
    pDWdest^ := pDWsour^ +1; (* W <= W throu pDW *)
    Опс. Здесь мы гробим pWsour. (Понятно как ?)
    И в :
    pWdest^ := pWsour^ +1; (* DW <= DW throu pW *)
    Пытаемся прочитать х.з. откуда, что иногда приводит к :

    Доступ по несуществующему адресу. ПЛК остановлен
    (Слава Богу, что мы не управляли котельней!)
    Её-то Михалыч отремонтирует. А если б а.реактором ?
    И если приспичило :

    pDWdest^[/U] := pDWsour^ +1
    то придется применять проктологические методы

    pDWdest^ := ( pDWdest^ and 16#FFFF_0000 ) or ( ( pDWsour^ + 1 ) and 16#0000_FFFF );

    Сможете пояснить смысл этого действа ?



    PS
    Взяли на понт. Остались детки без подарков .......
    Последний раз редактировалось Валенок; 01.12.2010 в 19:04.

  9. #9
    Пользователь Аватар для drvlas
    Регистрация
    30.09.2010
    Адрес
    Киев
    Сообщений
    700

    По умолчанию

    Спасибо, уважаемый Учитель! Проясняется... Или это похмел проходит?
    Цитата Сообщение от Валенок Посмотреть сообщение
    Ошибка 1. (Толстая)
    ...
    Ошибка 2. (Тоньше 1.)
    Смысл ошибок понятен, хотя натолкал-то я их специально, в тщетной надежде, что прокатит использование пойнтера на длинный тип данных при обращении и к коротким типам (о своей задаче ЩАС расскажу чуть подробнее).
    Цитата Сообщение от Валенок Посмотреть сообщение
    И если приспичило :
    то придется применять проктологические методы
    Код:
    pDWdest^ := ( pDWdest^  and  16#FFFF_0000 ) or  ( ( pDWsour^ + 1 ) and  16#0000_FFFF );
    Сможете пояснить смысл этого действа ?
    Думаю, что да, Учитель. Надеясь на определенный способ расположения многобайтных данных в памяти, мы пер анус обращаемся к ним "по частям" и "склеиваем" части. Только ты впиндюрил ошибочку, ИМХО. Надо
    Код:
    pDWdest^ := ( pDWsour^  and  16#FFFF_0000 ) or  ( ( pDWsour^ + 1 ) and  16#0000_FFFF );
    Верно?
    И, конечно же, это не есть гут. Ибо в хороших переносимых программах не привязываются к таким особенностям реализации (расположения в памяти).

    Цитата Сообщение от Валенок Посмотреть сообщение
    PS
    Взяли на понт. Остались детки без подарков .......
    Это судьба Русского Учителя, уважаемый. Космонавтов учит, премьер-министрам сопли вытирает, а сам в рваных штанах
    Неси свой крест! Мы тобой восхищены!

    А теперь постараюсь пояснить, почему мне изощрения, ИМХО, не помогут. Дело в том, что я собираюсь не знать при исполнении, каковы же реально типы данных под пойнтером... Но это заслуживает отдельного поста. ЩА СДЕЛАЕМ...
    ...барабанная дробь...

  10. #10
    Пользователь Аватар для drvlas
    Регистрация
    30.09.2010
    Адрес
    Киев
    Сообщений
    700

    По умолчанию вот откуда вопрос-то взялся

    У меня есть куча параметров работы (далее - параметров), которые имеют одно общее свойство: их может читать оператор и-или комп сверху.

    Сами по себе, это данные разных типов:
    - флаги отдельных свойств (ну, там можно BYTE юзать);
    - короткие пременные, тоже однобайтных хватает;
    - длинные переменные, как со знаком, так и без, некоторые требуют аж 4-х байт;
    - временнЫе данные, такие как время, дата, длительность разных пауз и задержек (до десятков секунд);
    - флоаты тоже. по сути работают. но я их постараюсь убрать и в качестве параметров не использовать.

    Эти данные имеют разные изменяемости:
    - неизменяемые переменные (типа номер версии ПО, задается при компилировании);
    - изменяемые программой, но не оператором (например, результат измерения или фаза работы);
    - изменяемые оператором и-или программой, но с разной "разрешительной системой", например, изменяемые только с кодом доступа или как попало;

    Эти данные еще имеют и разные свойства в смысле сохраняемости. Часть из них должна быть RETAIN, для остальных это бессмысленно. Часть параметров сохраняется вообще не в ПЛК, а в другом узле сети.
    Ну, и другие мелкие различия в порядке их редактирования, автоматического изменения и прочее - этим, скорее всего, придется пожертвовать ради великой Цели.

    А Цель такова: сделать работу с просмотром и редактированием параметров в одном участке кода. То есть, работать с параметром при его редактировании по его индексу. И все. Остальное предполагается извлекать из структуры PARSCRIPT, в которой есть вся необходимая инфо.
    В старом проекте (не на ПЛК) были просто огромные SWITCH-и и на каждый параметр свой CASE. Но там хоть привычная форма представления программ, в человеческих редакторах. В КОДЕСИС же (при всем уважении!) работать с огромными текстами неудобно.
    Да и вообще, считайте это моим капризом. "Хочу иконки, несмотря на социализм"

    Для реализации Цели я создаю такие элементы:

    1. Описание параметров.

    Код:
    TYPE PARSCRIPT :
    STRUCT
    	Numb:		BYTE;	(* Номер параметра по ЭД, 0...255 *)
    	Point:		BYTE;	(* Формат вывода: 0, 1, 2, 3 знака справа от точки *)
    	Mdf:		BYTE;	(* 0 prog RO, 1 user RO, 2 RW, 3 R(W в СТОПЕ), 4 R(W с паролем) *)
    	Node:		BYTE;	(* Место хранения параметра, 0 - в ПЛК, 1 - в ТП *)
    	Mini:		DINT;	(* Границы значения параметра *)
    	Maxi:		DINT;
    	Ptr:		POINTER TO DINT;(* Указатель на параметр *)
    	Name:		STRING(10);	(* Текст имени *)
    END_STRUCT
    END_TYPE
    2. Массив структур размером с количество параметров:

    Код:
    VAR_GLOBAL
    	apsPar: ARRAY [0..MAX_PAR_NMB] OF PARSCRIPT;
    END_VAR
    Этот массив с помощью функции set, подсказанной Учителем, заполняю при старте константами. В том числе, на место Ptr записываю адреса переменных-параметров:

    в фунции set есть строка

    Код:
    apsPar[ iParIndx].Name	:= Name;
    и функция вызывается многократно, на все параметры:

    Код:
    set( 101,	2,	0,	0,	0,	9999,	ADR(Dummy),			'Версия ПЛК');
    set( 102,	2,	0,	0,	0,	9999,	ADR(Dummy),			'Версия ТП');
    set( 103,	0,	4,	0,	1,	31,	ADR(_103_Addr_IP),		'Адр с ИП');
    set( 104,	0,	4,	0,	0,	5,	ADR(_104_Baud_IP),		'Скор с ИП');

    3. Собственно параметры, разных типов, сохраняемые и нет:

    Код:
    VAR_GLOBAL RETAIN
    (* Сохраняемые  П А Р А М Е Т Р Ы  работы ПЛК *)
    	_103_Addr_IP:	BYTE := 1;	(*Адрес для работы с ИП320 *)
    	_104_Baud_IP:	BYTE := 5;	(*Код 0-5 скорости работы *)
    ...
    (* Конец области задания П А Р А М Е Т Р О В *)
    END_VAR
    
    VAR_GLOBAL
    (* Не сохраняемые П А Р А М Е Т Р Ы  работы ПЛК *)
    	_120_ADC:		DINT;		(* Код АЦП *)
    	_170_Phase:		BYTE;		(* Фаза работы *)
    ...
    	_185_Time2Unld:	TIME;			(* Время до разгрузки *)
    	_186_Errors:		WORD;		(* Слово ощибок (аварий) *)
    (* Конец области задания П А Р А М Е Т Р О В *)
    END_VAR
    Дальше я еще не написал, т.е. все неприятности по поводу чтения и редактирования параметров оператором - впереди.
    Но уже сейчас понятно, что объявление в PARSCRIPT

    Код:
    Ptr:	POINTER TO DINT;	(* Указатель на параметр *)
    вызовет проблемы для тех параметров, которые вовсе не DINT.

    Как же быть? Как доступаться к параметрам, имея на руках только указатель, если параметры разные по типам?
    Последний раз редактировалось drvlas; 02.12.2010 в 11:11.

Страница 1 из 4 123 ... ПоследняяПоследняя

Ваши права

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