PDA

Просмотр полной версии : Проверка на Null указателей



Спорягин Кирилл
21.08.2015, 15:08
Добрый день.

Как в CDS осуществить проверку указателя на Null?

amn
21.08.2015, 16:05
Проверяйте равенство указателя с нулем.

capzap
21.08.2015, 16:15
Добрый день.

Как в CDS осуществить проверку указателя на Null?

в КДС не может быть типа данных null, поэтому и проверка не нужна

Спорягин Кирилл
21.08.2015, 16:43
Проверяйте равенство указателя с нулем.

Спасибо. Так и делал. Но хотел убедиться.

amn
21.08.2015, 17:12
Вообще-то я так никогда не делаю, не знаю где это может понадобиться. :)

Валенок
22.08.2015, 11:05
Вообще-то я так никогда не делаю, не знаю где это может понадобиться. :)
Например маркер конца списка.
По теме, имхо, красивше константа (null,nil...) dword/dint и сравнение с ней

capzap
22.08.2015, 11:31
Например маркер конца списка.
По теме, имхо, красивше константа (null,nil...) dword/dint и сравнение с ней

пример будет? Что такое список? если указатель ушел дальше объекта, почему там должен быть какой то null. Еще допускаю если речь бы шла в частном случае о NaN

Валенок
22.08.2015, 11:44
plist ->(pnext->)->(pnext->)->(pnext=nil)
простейший односвязный список из 3х объектов.

PS
Прогон неких фб из списка

pcurrent := plist;
while pcurrent <> nil do
pcurrent^(pnext => pcurrent);
end_while

обмен/архивация/события/...

capzap
22.08.2015, 12:43
plist ->(pnext->)->(pnext->)->(pnext=nil)
простейший односвязный список из 3х объектов.

PS
Прогон неких фб из списка

pcurrent := plist;
while pcurrent <> nil do
pcurrent^(pnext => pcurrent);
end_while

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

Валенок
22.08.2015, 13:24
В данном случае - искусственный т.к. является принудительно устанавливаемым при инициализации объекта в выделенном куске памяти.
Но вот при выделении самого участка памяти для объекта (из кучи) - может вернутся и случайный что будет является всего лишь признаком невозможности расширении списка а не перезагрузки ПЛК.

Любой проект является как бы (С) а возможные области применения я показал. Именно там я их и применяю.

Например архивация.
Объекты генерят события в динамический список.
При ненаступлении некоторых критических событий часть событий самоуничтожается (чтоб не плодить избыточную инфу)
Архиватор формирует из нужных событий буфер
Буфер при превышении 512 байт сливает окно (512 байт) в архив флеша
Рез-т : Имеем архив важных событий с подробной ситуацией перед наступлением аварий.

capzap
22.08.2015, 13:40
Но вот при выделении самого участка памяти для объекта (из кучи) - может вернутся и случайный

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

Валенок
22.08.2015, 21:09
Ну так и есть - случайное образование nil при вызове выделителя памяти
Используемая инициализация объекта с полем pnext (выше) - принудительная установка
Но для проверяющего список - появление nil в поле pnext текущего объекта опять же - случайное. Проверяющий не знает заранее кол-во элементов в списке. Ему это вообще побоку. Он вообще в библиотеке. Вводить дополнительную сущность ?

PS
Изв. за перерыв. Шашлык не ждет

capzap
23.08.2015, 07:43
что есть список? в МЭК нет такого оператора, если это что то своё, то стоит позаботиться то методе size() чтоб проверяющий мог знать количество элементов. Если это массив строк, то на место удалённых обычно смещают последующие элементы, не могу я представить появление null-об'ектов в КДС

Yegor
23.08.2015, 18:50
типа данных nullnull сам по себе традиционно не является и не относится к типам данным. Это самостоятельная лексическая единица, обозначающая неинициализированный указатель. Без неё можно жить. C++ обходился и обходится без поддержки null со стороны компилятора, но в C++11 (2011) литерал nullptr был введён на замену устоявшейся нулевой константе NULL, вместо которой можно писать просто 0.
что есть список?Список есть совокупность смежно-связанных элементов. Следует различать массив и список (массив есть совокупность смежно расположенных в памяти элементов). В отличие от массива, для функционирования списка не требуется определение его размера, но при этом отсутствует произвольный доступ за константаное время по индексу элемента (как следствие неопределённого размера и расположения элементов в памяти — требуется обход с попутным вычислением индекса). Возможны смешанные реализации.
чтоб проверяющий мог знать количество элементовПрактика программирования такова, что списки чаще используют там, где не требуется знать количество элементов. Вы начинаете обход списка с заранее известного элемента (чаще с головы или хвоста) и продолжаете до тех пор, пока вам не надоест или не попадётся пустой указатель (0, NULL, NIL, nullptr и т.д.) на следующий элемент, что и будет означать конец списка во взятом вами направлении.

Валенок
23.08.2015, 19:28
Егор замечательно все сказал. Чисто добавить :

введён на замену устоявшейся нулевой константе NULL, вместо которой можно писать просто 0..
Ключевое слово - константа. Именованные константы повышают читабельность и переносимость.
Хоть и везде несуществующий указатель это 0, но писать 0 или NULL - это из серии выбирать между 0/1 и TRUE/FALSE (в КДС). Без разницы, но лично я всегда пишу TRUE/FALSE.

capzap
23.08.2015, 20:52
тут точно все говорят про мэк, в яве я пользуюсь проверкой на null, на здесь у меня в окне объявлений компилятор не допустит непринициализированный объект.
что касается списков, я знаю обобщенно два вида списков, нумерованный (enum) и list, первый насколько понимаю встречается в кдс и там нам известно в каких случаях будет null
по поводу нуля, указатель вернувший ноль, мне кажется совсем не то, что указатель на тип null, это я про то как звучит вопрос темы

зы кого то вот шашлыки ждут, а меня Уфа, т.ч. проверить все вышесказанное в кдс не смогу)

Валенок
23.08.2015, 23:16
про тип null Егор уже сказал.
автор темы, предполагаю, имел ввиду как кто проверяет указатель на предмет того а указывает ли он.

capzap
24.08.2015, 00:54
а что Егор сказал такого про null, применительно в КДС, например указатель на реал, ткните его в любую точку памяти, когда это он вернет null?

Валенок
24.08.2015, 01:42
Не вернет, а сам есть null

var
p : pointer to real;

capzap
24.08.2015, 03:38
Не вернет, а сам есть null

var
p : pointer to real;

и какова же в таком случае должна быть проверка, на этапе загрузки проекта в плк проверить неиспользуемые переменные

Yegor
24.08.2015, 07:19
Вот напишу я вам библиотеку, в которой одна из функций будет возвращать указатель (адрес) на буфер, и скажу, что в случае неудачи эта функция возвращает NULL (0). На этапе загрузки вы с этим ничего сделать не сможете. Вам придётся в своей программе проверять значение, возвращённое моей функцией, чтобы оно не оказалось равным нулю. Буквально IF ptr <> 0 THEN... Так?

В Жаве в аналогичной ситуации вы бы написали if (xyz != null) и никак иначе, потому что там модель ссылочная, адреса скрыты от программиста, ссылки в чистом виде не являются для программиста числами, и следовательно, сравнивать их с нулём нельзя — из-за чего и введена литера null (не является типом и не имеет своего типа; это своеобразный нолик для проверки и инициализации ссылок любого типа). UPD: спеки на Жаву в п. 4.1 (http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.1) говорят, что null таки имеет свой тип, но этот тип не имеет имени. In practice, the programmer can ignore the null type and just pretend that <code class="literal" style="color: rgb(0, 0, 0); font-size: 10.1999998092651px; font-style: italic; line-height: 16.7999992370605px;">null</code> is merely a special literal that can be of any reference type.

Но некоторые идут из страны весёлых языков Си/Си++. Особенно Си++. Ссылочная система там гарантирует, что объект будет валидным — null как в Жаве не требуется, и его нет. Но помимо неё есть ещё указательная система, и адреса под указателями имеют неявно числовой тип и могут быть какими угодно. До 2011 года полученные извне адреса сравнивали с нулём. Но для читаемости и чтобы не путать указатели с числами вместо нуля часто писали NULL (глобально определённая библиотечная константа, которая на самых первых этапах компиляции подменялась нулём). По той же причине люди пишут TRUE/FALSE вместо 0/1, как Валенок выше уже упомянул. А в 2011 стандартом на замену этому колхозу был введён литерал nullptr, который уже поддерживается на уровне компилятора как null в Жаве, но для указателей, а не для ссылок.

И вот SKV спрашивал, есть ли что-то вроде NULL/nullptr из мира Си++ (или ещё откуда). Ответ отрицательный: указатели придётся сравнивать с нулём или определить для себя константу с именем NULL.

capzap
24.08.2015, 12:52
Вот напишу я вам библиотеку, в которой одна из функций будет возвращать указатель (адрес) на буфер.да не буду я пользоваться функцией, которая возвращает всё что угодно, скорее всего в таком случае перейду на яву, если это не решается в плк. И кста в ней , не обязательно буду возвращать null, лучше выбросить исключение. И еще если я объекту присвою null то он отправится в мусор и должен освободить ресурсы, в плк присвоив указателю ноль, он всёравно будет занимать двойное слово, а объект на который ссылался останется в памяти и надеюсь тоже сотрется со временем, а не останется занимать ресурсы

Yegor
24.08.2015, 14:17
Не всё что угодно, а нуль при неуспешном завершении. Это слишком распространённый приём, чтобы взять и махнуть на него рукой.

Существование и инициализированность указателя никак не влияют на время жизни объектов. Сборка мусора, когда она вообще есть, работает подсчётом ссылок. Указатели — не ссылки, а ссылки — не указатели.

capzap
24.08.2015, 15:15
я предпочитаю создать буфер, а в функцию передать указатель для его обработки

Валенок
24.08.2015, 15:29
Тогда код функции будет иметь проверку Вашего указателя на 0

Спорягин Кирилл
24.08.2015, 16:49
Вот для чего я собираюсь использовать проверку на null.

FUNCTION_BLOCK DispatcherModbus

VAR_INPUT
pModule : ARRAY[1..247] OF POINTER TO ModuleBase;
END_VAR

pModule - массив указателей на модули.
При первом вызове DispatcherModbus, я должен передать ссылки на все модули, которые у меня есть в системе.
Остальные остаются равными null. Затем в диспетчере я проверяю, есть ли модуль проверкой на null.

Так что проверка нужна.
Спасибо за совет использовать константу вместо 0, действительно, красивее.

capzap
24.08.2015, 18:11
Тогда код функции будет иметь проверку Вашего указателя на 0

я не отрицаю что проверки понадобятся, но могу использовать sizeof, а в функции через цикл прогнать, пускай даже нулевое количество циклов, только бы не по Вашему было :)
только всё равно не понимаю, как инициализированный буфер может не получить указатель, который Вы заставляете меня проверять, а уж инициализировать массив NULL значениями, эх, я так не умею

Валенок
24.08.2015, 20:53
только бы не по Вашему
как компромисс - можно так
if p < 1 then


а уж инициализировать массив NULL значениями, эх, я так не умею
а вот

FUNCTION_BLOCK DispatcherModbus

VAR_INPUT
pModule : ARRAY[1..247] OF POINTER TO ModuleBase;
END_VAR

capzap
25.08.2015, 06:10
а вот ...
у меня так рука не поднимется, я бы написал: pModule : ARRAY[1..247] OF DWORD := 0(247);
и то чтоб проверить
а на самом деле так проекты не пишутся, через бибку у меня вообще не встанет вопросов с адресацией, ООП в КДС2 не существует, поэтому ModuleBase это частный случай и универсальности от него ноль, полюбому писать реализацию каждый раз свою и под каждое устройство другого типа, про то чтобы держать в конфигураторе слейвы более 32 штук у меня сразу вопрос а тот ли контроллер выбрал человек

Спорягин Кирилл
25.08.2015, 11:21
у меня так рука не поднимется, я бы написал: pModule : ARRAY[1..247] OF DWORD := 0(247);
и то чтоб проверить
а на самом деле так проекты не пишутся, через бибку у меня вообще не встанет вопросов с адресацией, ООП в КДС2 не существует, поэтому ModuleBase это частный случай и универсальности от него ноль, полюбому писать реализацию каждый раз свою и под каждое устройство другого типа, про то чтобы держать в конфигураторе слейвы более 32 штук у меня сразу вопрос а тот ли контроллер выбрал человек

Если написать так: pModule : ARRAY[1..247] OF DWORD := 0(247);, то у Вас будет массив DWORD и как Вы будете обращаться к полям структуры ModuleBase не понятно. А я это делаю вот так:
if pModule[1]^.ReqForPooling then ....
Структура ModuleBase содержит поля, которые должны быть у любого модуля. Эти поля отвечают за организацию опроса. А вот остальная реализация модуля у каждого типа модулей, действительно, своя. Один обращается к регистрам хранения, другой к входным регистрам. Один читает 2 регистра, другой 8 и т.д. и т.п.
Одним словом ModuleBase - это базовый тип всех модулей. Конечно, организовать классическое ООП не получится, но писать в стиле приближенным к нему можно.

capzap
25.08.2015, 11:59
Одним словом ModuleBase - это базовый тип всех модулей. Конечно, организовать классическое ООП не получится, но писать в стиле приближенным к нему можно.
только в КДС3 можно расширить базовый класс, в двойке только новое ПОУ
по поводу DWORD-ов, а какой размерности указатель по Вашему?

Спорягин Кирилл
25.08.2015, 12:21
Указатель-то размерности dword, но если вы объявите так как предлагаете, то не сможете работать с полями ModuleBase.

capzap
25.08.2015, 12:49
Указатель-то размерности dword, но если вы объявите так как предлагаете, то не сможете работать с полями ModuleBase.

ой ли, Вы проверяли?

Спорягин Кирилл
25.08.2015, 13:02
Вы фактически передаете тоже указатель на Base. Только зачем-то его объявляете, как dword?

capzap
25.08.2015, 13:11
первое что в голову приходит, писать меньше :)
с двордом у меня нет необходимости прописывать указатель на какой объект я собираюсь обрабатывать