OAR>> А что здесь непонятно?!
OAR>> QueRef обьявлен как УКАЗАТЕЛЬ НА ОЧЕРЕДЬ.
OAR>> При передаче его как ANY компилятор предполагает, что
OAR>> в процедуру передается БУФЕР ЗАПИСИ ОЧЕРЕДИ на которую
OAR>> указывает QueRef.
OAR>> И, соответственно, его действия следующие:
OAR>> — по указателю QueRef читает заголовок очереди, на которую
OAR>> ссылается QueRef
OAR>> — из заголовка выбирает указатель на буфер записи этой
OAR>> очереди
OAR>> — по выбраному указателю создает UFO-обьект типа GROUP
OAR>> — передает его в процедуруAA> …
AA> QueRef &= NULL
AA> MyProc(QueInst, QueRef)
AA> …AA> каков будет результат? QueRef ведь ИНИЦИАЛИЗИРОВАН???
OAR>> Как видно, уже на первом шаге произойдет GPF, т.к. перед
OAR>> вызовом процедуры QueRef НЕ ИНИЦИАЛИЗИРОВАН, т.е.,
OAR>> грубо говоря, QueRef &= NULL!!!AA> ну ежели компилятору самому в облом инициализировать указатели
AA> каким-либо значением (пусть даже NULL), то уж как-то он (runtime)
AA> должен отслеживать валидность указателей…
Я, очевидно, неверно обьяснил.
Под ИНИЦИАЛИЗАЦИЕЙ понимается присвоение указателю значения ОТЛИЧНОГО от нуля, т.е. от NULL.
Я же написал, что согласно принятой схеме превращения указателя на очередь в ANY-обьект, сначала производится чтение заголовка очереди на которую ссылается QueRef. А так как QueRef &= NULL, то, соответственно, получим чтение из ячейки памяти с НУЛЕВЫМ АДРЕСОМ, что, естественно, приведет к GPF!
А о том, что у Клариона проблемы с проверкой валидности указателей, я уже давно и неоднократно писал. По моему мнению, именно такое отношение к обработке указателей является причиной ~80%-90% ошибок Клариона! Хотя, вообще-то, это не столько ошибки Клариона, сколько ошибки C-библиотеки, на которой базируется ядро RTL, и ошибки компилятора, которым оттранслировано это ядро. Ну и, естественно, небрежное или невнимательное отношение самих разработчиков к данной проблеме.
Казалось-бы, чего проще — ВСЕГДА при входе в процедуру сразу проверять переданные указатели на валидность? И, кроме этого, попутно делать такие проверки непосредственно ПЕРЕД обращением к ячейке памяти. Типа:
if QueRef &= Null then Return. ... Peek(QueRefAddr,QueHeader) if ~QueHeader.BuffPtr then Return.
OAR>> Надеюсь, что я понятно обьяснил данную ситуацию?
AA> ага…только как быть в случае, если я хочу инициализировать
AA> QueRef внутри MyProc(…) ???
Ну, здесь надо немного по другому. Так сказать, необходимо обмануть слишком интеллектуальный компилятор Клариона. Благо — он (компилятор) довольно легко поддается обману:)
MAP MyProc(*QUEUE _Que),LONG END Code QueRef &= MyProc(QueInst) Return MyProc PROCEDURE(*QUEUE _Que) RefGrp GROUP qRef &QUEUE END lRef LONG,OVER(RefGrp) Code RefGrp.qRef &= _Que Return(lRef)
Вот теперь, после отработки процедуры, реферал QueRef будет ссылаться на очередь QueInst.
AA> Я понимаю, что это — «особенности» Клариона :))
AA> Обиднааа тока когда на них наступаешь… 🙁
Да, это именно ОСОБЕННОСТИ (без кавычек) языка Кларион! У него, как впрочем и у других языков, есть свои особенности, которые необходимо знать и учитывать. Другое дело, что многие такие особенности или совсем не документированы, или документированы неполно.
AA> кстати: С5ее — win32
AA> вот такая вот ситуация с передачей ссылки по ANY приводит к краху.
AA> Хотя с точки зрения компилятора никакого криминала тут нету.
PROGRAM MAP MyProc(*QUEUE Q, *ANY F) . Que QUEUE,TYPE F1 LONG F2 LONG . QueInst Que QueRef &Que CODE MyProc(QueInst, QueRef) MESSAGE('Ok') MyProc PROCEDURE (*QUEUE Q, *ANY F) CODE
! тут что-то делаем (если досюда доберемся 🙂
А что здесь непонятно?!
QueRef обьявлен как УКАЗАТЕЛЬ НА ОЧЕРЕДЬ. При передаче его как ANY компилятор предполагает, что в процедуру передается БУФЕР ЗАПИСИ ОЧЕРЕДИ на которую указывает QueRef.
И, соответственно, его действия следующие:
по указателю QueRef читает заголовок очереди, на которую ссылается QueRef из заголовка выбирает указатель на буфер записи этой очереди по выбраному указателю создает UFO-обьект типа GROUP передает его в процедуру
Как видно, уже на первом шаге произойдет GPF, т.к. перед вызовом процедуры QueRef НЕ ИНИЦИАЛИЗИРОВАН, т.е., грубо говоря, QueRef &= NULL!!!
Для нормальной работы необходимо сделать что-то типа:
QueRef &= QueInst MyProc(QueInst,QueRef)
Вот теперь все отработает без ошибок и в процедуру будет передан указатель на очередь QueInst и ANY-ссылка на буфер записи этой-же очереди.
Надеюсь, что я понятно обьяснил данную ситуацию?
AA> Допустим, что где-то там имеются некие очереди
Q1 QUEUE UserID LONG UserName STRING(100) END Q2 QUEUE DepartmentID LONG UserID LONG BossName STRING(100) UserName STRING(100) END
AA> Эти очереди используются локально в каких-то процедурках. И апосля
AA> того, как пользователь чего-то там поменял, нам требуется обновить БД.
AA> Логично «нарисовать», скажем:
UpdateUsersName (*QUEUE Q), BOOL CODE ! было бы хорошо использовать тута Q.UserID ! но компилятор понятия не имеет о полях передаваемой очереди ! посему вот тут и логично использовать поиск по имени поля ! оно-то ведь всегда есть :) LOOP i# = 1 TO RECORDS(Q) GET(Q, i#) IF GetFieldValueByName (Q, 'UserID', UserID#) AND GetFieldValueByName (Q, 'UserName', UserName) ! обновить(добавить) запись БД . .
AA> Вот для подобных вещей, на мой взгляд, и удобно использовать
AA> нетитпизированные очереди(группы). Фиг с ней, со структурой — главное
AA> штоб нужные поля были 🙂
Может я чего не понял — после праздников, думаю, простительно:) Или от того, что не читал начала данной темы — на довольно длительное время был «отлучен» от компа.
Вот почитал несколько писем по данной теме и подумал — а зачем, собственно, чего-то изобретать, писать какие-то функции?! А что, типизированные очереди уже отменили? Или, может, отменили наследование очередей?
Конкретно, вышеописанная задача решается с пол-пинка таким
образом:
MAP UpdateUserName(Q1 _Que) END Q1 QUEUE UserID LONG UserName STRING(100) END Q2 QUEUE(Q1) DepartmentID LONG BossName STRING(100) END Code ... UpdateUserName(Q2) ... Return UpdateUserName PROCEDURE(Q1 _Que) Code LOOP I# = 1 TO RECORDS(_Que) GET(_Que,I#) IF _Que.UserID AND _Que.UserName ! обновить(добавить) запись БД . . Return
Если первая очередь Q1 не рабочая, т.е. используется только как прототип, то можно сделать ее типовой, добавив аттрибут TYPE.
Ну, и что здесь сложного?
А по поводу предыдущих писем по данной теме, где Андрей сетовал на какие-то трудности с обьявлением типизированных очередей, хотелось-бы услышать хотя-бы одну из них!? Тем более, что, как он уже писал, код пишеться полностью руками.
Или трудно завести что-то типа типизированной очереди Q1 с полями, которые присутствуют во всех остальных подобных очередях, и наследовать потом эти очереди от нее?
Вот, честное слово — сколько работаю с очередями — еще НИ РАЗУ не было НИКАКИХ проблем с обработкой очередей, передаваемых в качестве параметров в процедуры!
Другое дело, если речь идет об УНИВЕРСАЛЬНОМ механизме работы с очередями. Тогда можно и потеоретизировать! Хотя, как и всякий универсализм, этот подход влечет за собой довольно приличные накладные расходы на скорость выполнения. Да и с обработкой массивов будут проблемы.