Архивы автора: Evgeny Stefanenko


… переменная MyValue так и остается UFO-переменной с типом ULONG …

>> Но! Именно из-за того, что в процедуре не происходит преобразование
>> типа, переменная MyValue так и остается UFO-переменной с типом ULONG.
>> А UFO-переменные ЛЮБОГО типа перед арифметическими операциями ВСЕГДА
>> преобразуются в тип REAL. Именно из-за этого преобразования значение
>> x80000001 становиться x80000000!!!
>> Ну а дальше — понятно: BXOR(x80000000,x80000000) = 0!

Если передать в процедуру LONG переменную она тоже UFO?
Но почему с ней все происходит корректно, если она тоже преобразуется к REAL?

Как я уже писал, в REAL-тип преобразуется любая переменная.
Другое дело, как это преобразование происходит! Хотя, в случае с LONG и ULONG переменными генерится абсолютно одинаковый код преобразования. Так что, или компилятор не прав и надо генерить другой код, или такие чудеса вытворяет сопроцессор, через чьи регистры и команды происходит это преобразование.

Кто нить может объяснить сей феномен (C5ee-b)

Кто нить может объяснить сей феномен (C5ee-b):

  PROGRAM
  MAP
    ChangeValue(*? MyValue)
  END

 TstValue           ULONG

  CODE
  ! Так нормально
  TstValue = 1                             ; MESSAGE(TstValue)
  TstValue = BOR (TstValue, BSHIFT(1, 31)) ; MESSAGE(TstValue)
  TstValue = BXOR(TstValue, BSHIFT(1, 31)) ; MESSAGE(TstValue)

  ! А так нет, TstValue обнуляется после BXOR
  ChangeValue(TstValue)

 ChangeValue        PROCEDURE(*? MyValue)
  CODE
  MyValue = 1                            ; MESSAGE(MyValue)
  MyValue = BOR (MyValue, BSHIFT(1, 31)) ; MESSAGE(MyValue)
  MyValue = BXOR(MyValue, BSHIFT(1, 31)) ; MESSAGE(MyValue)

Когда TstValue LONG, работает нормально.

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

Во-первых, при передаче ULONG-переменной через не типизированную ссылку СОХРАНЯЕТСЯ тип ULONG. Так что, никаких преобразований на данном этапе не происходит. Во-вторых, исходя из первого — понятно, что и в процедуре не происходит никаких явных или неявных преобразований к LONG-типу.

Но! Именно из-за того, что в процедуре не происходит преобразование типа, переменная MyValue так и остается UFO-переменной с типом ULONG. А UFO-переменные ЛЮБОГО типа перед арифметическими операциями ВСЕГДА преобразуются в тип REAL. Именно из-за этого преобразования значение x80000001 становиться x80000000!!! Ну а дальше — понятно: BXOR(x80000000,x80000000) = 0!

Так что, это — не глюк Клариона. Точнее — не совсем глюк, а документированная фича! Из-за подобной фичи, например, невозможно во View-фильтр прямо передавать ULONG-константы.

Есть процедура в которой обрабатывается глобальная очередь…

Столкнулся со следующей проблемой:
Есть процедура в которой обрабатывается глобальная очередь

GloQueue             QUEUE,TYPE
ID                            LONG
                             END
MyQueue           &GloQueue, THREAD

В пределах одного модуля пишу процедуру с описанием myProc ( Queue, long, long ) вызываю ее из этого же модуля —  myProc ( MyQueue, MyQueue.ID, curNumber ) Читать далее

GET на очередь с ANY

VY> 1.В чем отличие (в данном контексте) между операторами:
VY> RefQue &= WHAT(AnyQue, 1) и RefQue &= WHAT(AQ:ID)

Ты, вероятно, имел в виду:

RefQue &= WHAT(AnyQue,1) и RefQue &= AQ:ID

Отличие очень большое!
В первом случае оператор WHAT() не обрабатывает, как положено, поле типа ANY. Это — известная недоработка таких оператор, как WHAT/WHO/WHERE. Я уже как-то описывал все особенности их работы.
Так вот, в данном случае, WHAT() просто формирует внутреннюю UFO-переменную (внутренний аналог ANY) и назначает ей ссылку на 4-байтовую область памяти по адресу, равному адресу поля AQ:ID в буфере записи очереди AnyQue. Читать далее

Проблемка в фильтре VIEW

А никто не замечал, что фильтр от VIEW не понимает ULONG-чисел, заданных явно?!
Т.е., такой вот фильтр, например, будет работать неверно:

BrwView{PROP:Filter} = 'DOC:Index > 4000000000'

В итоге, фильтр преобразует число в LONG и выдаст все документы с индексами больше чем -294967296, что, как Вы понимаете, «немного» не то, что просили! Преобразование в LONG происходит не компилятором а именно драйвером обработки VIEW.

Для решения данной проблемы надо завести ULONG-переменную (глобальную или локальную — не важно) и забиндить ее:

ULongVar  ULONG

  Code
  BIND(ULongVar)
  ...
  ULongVar = 4000000000
  BrwView{PROP:Filter} = 'DOC:Index > ULongVar'

Вот теперь View правильно отберет документы с индексами больше чем 4 млрд.

Интересно, это — ошибка или так и должно быть?
Я так думаю, что это — именно ошибка. Так как я, в случае необходимости, могу явно задать негативное число, вместо того, чтобы гадать — преобразует View его или нет.

SET() и всякие глупости

>> >> >> А че будет, ежли и правда ключ чему-то приравнять? :-)))
>> >> AM> не понял, ключ приравнять то конЭчно нельзя а вот группу можно
>> >> AM> получилось то что ты и хотел, те групповое присвоение полей в СО> ключе, это
>> >> AM> имелось ввиду ?
>> >> Дык группы присваивать я уже умею ;). А то было б непосредственно ключ
>> >> 🙂
>> VVS> Вот более непонятно отсутствие ошибки при использовании
>> VVS> ключей не от тех файлов в файловых операциях.
>> VVS> Типа SET(File1:Key,File2:Key) и т.п.

СО> есть подозрение что File1:Key,File2:Key — это просто порядковый номер ключа
СО> SET(1,1) — Может работать…. Грубо и наверно не так.
СО> Хотя есть подозрение что в результате вынимается номер ключа….

Немножко не так.

На самом деле все достаточно просто: в данной форме оператора SET() второй параметр используется ТОЛЬКО для определения самой операции — «выставить указатель в ключе по полям данного ключа». А само значение этого второго параметра драйвером не используется. Поэтому в качестве второго параметра может стоять ЛЮБОЙ ключ. Все данные о рабочем файле и ключевым полям берутся из ключа, заданного в качестве первого параметра.

Другое дело, что выглядит это малость странновато и должно бы пресекаться на этапе компиляции. Хотя думаю, что знаю, почему компилятор не делает подобной проверки — в качестве параметров оператора SET() могут быть использованы рефералы на ключи. А их принадлежность какому-либо файлу можно определить ТОЛЬКО во время выполнения.

Кстати! В рамках данной темы поднимался вопрос о сравнении скорости работы цикла чтения записей прямо из файла или посредством View. Как показывает опыт (и не только мой), чтение через View практически НИКОГДА не бывает медленнее прямого чтения из файла. Но, во многих случаях, чтение через View быстрее прямого чтения из файла. Иногда — на порядок!

Основные преимущества по скорости у View в следующих случаях:

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

Небольшое дополнение к первому пункту: при использовании фильтра, который не «ложиться» ни на один из имеющихся ключей, разница в скорости выборки будет тем больше, чем меньше кол-во записей, удовлетворяющих всем условиям выборки.

SET()

PS> Здравствуйте, люди!
PS> Хочу выбрать из большого файла записи со значением полей: code_doc=8 и
PS> gBegDate<=data_last и data_last<=gEndDate. Чтобы не просматривать весь файл,
PS> я решил создать ключ из code_doc и data_last, потом установить режим прохода
PS> по файлу по этому ключу и прыгнуть на первую запись, у которой нужный
PS> code_doc (8). Как это сделать? Насколько я понял, с помощью оператора SET().

PS>   Строчка из описания файла:
PS> code_date_key KEY(MOV:code_doc,MOV:data_last),DUP,NOCASE,OPT

PS>   Кусочек программы:
PS>   OPEN(moving)
PS>   MOV:code_date_key=8
PS>   SET(MOV:code_date_key, < ? > )
PS>   LOOP UNTIL EOF(moving) OR (MOV:code_date_key<>8)
PS>      NEXT(moving)
PS>      ….
PS>   END
PS>   Что здесь неправильно и что должно стоять в качестве второго параметра
PS> SET? Надо ли присваивать что-то MOV:data_last ? Ну тогда уж минимальное
PS> возможное значение, т.к. меня интересуют все даты с этим code_doc. А какое
PS> оно?

Практически на все вопросы данного письма коллеги уже дали ответы. Но, кажется, остался один вопрос без ответа — см. последний абзац. Для присвоения какой-либо переменной наименьшего, возможного для данного типа, значения достаточно Читать далее

Свои библиотеки (в исходном тексте)

PS>   С неиспользуемыми кусками кода все понятно — это свойство компилятора, а
PS> не линковщика. С lib-модулями — тоже. Например, в Borland C++ lib-файлы
PS> (библиотеки) собираются из obj-файлов с помощью специальной программы.
PS>   А вот с obj-файлами — непонятно. Копирую их другого своего письма:
PS>   Может ли obj-файл, созданный компилятором при
PS> компилировании одной программы, использоваться в другой? Если не может —
PS> тогда понятно (он — «собственность» этого проекта). Если может — что
PS> наиболее вероятно (компилятор пишет что-то вроде «Создан qwe.obj (qwe.clw
PS> был изменен)») — то что, собственно говоря, помещать в этот obj-файл —
PS> процедуры, используемые в одном проекте, или процедуры, используемые в
PS> другом проекте? А если я создам один exe-файл, потом — другой, а потом
PS> вернусь к первому, что делать компилятору с obj-файлами? Как он узнает, что
PS> они были созданы для другого проекта?
PS>   А откуда Вы знаете про SmartLink? Наверное, там это объясняется.

Честно говоря, я этим делом специально не занимался. Но по опыту использования SOURСE — библиотек типа тех, что мы обсуждали по данной теме, могу сказать, что проблем никогда не было. Т.е., когда я собираю приложение, никогда не задумываюсь, а как у меня там с obj-модулями общих библиотек?

Стало интересно — посмотрел. Оказывается — все несколько не так Читать далее

Управление линковкой

NT> Можно собрать ToDo-заглушки для библиотек B или условно omit-ить вызовы.

Заглушки не подходят — некрасиво:) OMIT-ить вызовы не получится, так-как библиотека уже собрана и откомпилирована а условия конечной сборки определяются в самом приложении.

Вообщем, я уже решил эту проблему — в самом INC-файле основной библиотеки, используя COMPILE(), объявляю адресные метки всех «плавающих» переменных/процедур из подчиненных библиотек. А в главной библиотеке есть только список их адресов. При сборке библиотеки он пустой. Теперь, при сборке приложения, надо только с помощью Define-меток указать, какие переменные/процедуры будут использоваться в данном приложении и с помощью процедуры регистрации из главной библиотеки заполнить список адресов. Все это делает шаблон. Таким образом, получили эмуляцию динамического определения нужных адресов в статическом режиме! И линкер не ругается, и все работает.

В принципе, все это необходимо для новой библиотеки DynaFile. В этой библиотеке мне необходимо знать точки входа в файловые драйверы. В DLL-режиме их определить элементарно. А в статике их можно определить только если нужные LIB-библиотеки уже подключены к проекту. А так как эти точки входа определяются по символьным меткам драйверов, то эти самые символьные метки надо объявить в библиотеке. А если метка объявлена, но драйвер не подключен, то получаем отлуп от линкера. Вот и получается, что все драйверы подключать к проекту — нонсенс, а знать их адреса в библиотеке надо! И никакие условия компиляции уже не помогут, так как библиотека уже собрана.

>> А вот в данном случае — в библиотеке (А) обьявлено несколько
>> переменных или процедур, которые находятся в нескольких разных
>> библиотеках. При определенных условиях, в приложении некоторые
>> из этих переменных или процедур будут не нужны. Не хотелось-бы и
>> «цеплять» лишние библиотеки, которые не будут использованы.
>> Можно, конечно, для разных таких случаев собрать разные
>> варианты библиотеки (А). Но таких вариантом может быть масса.
>> Да и не красиво это как-то!

Address of FILE-driver

MAP
  ClarionDrv,NAME('CLARION')
  TopSpeedDrv,NAME('TOPSPEED')
END

Code
ClaDrvAddr# = Address(ClarionDrv)
TpsDrvAddr# = Address(TopSpeedDrv)

Compile project in Local mode. If drivers CLARION and TOPSPEED linked to project — all Ok.

If driver CLARION or TOPSPEED not linked to project — failed proccess of link. Ok. It is possible to make so, that the process of assembly of the project has not discontinued, and instead of addresses to receive 0?