Karrakurt
Участник
Offline
|
|
« : 19-12-2011 13:36 » |
|
Здравствуйте, хотелось бы получить ответы на несколько вопросов по Дельфи и дабы не плодить много тем решил все задать в одной, если это не правильно, сильно не пинайте, в следующий раз исправлюсь. 1) - При использовании подпрограмм во время передачи параметров в них, передается содержимое переменных или только указатель на переменную или там вообще другой принцип? Например объявив процедуру Test(Par : Byte), во время ее вызова ей передается байт информации или просто увеличивается счетчик ссылок на нее? Это я все к обработке больших переменных. 2) - Вопрос о булевых операциях, есть два известных мне способа работы с битами(булевы множества я не использую, пока не разбирался с ними): расчет маски и использование готовой маски. Например используя функции: установка бита в единицу Result := Param OR (1 shl BitNumb); Result := Param OR BitMask;
Сброс бита в ноль Result := Param AND NOT (1 shl BitNumb); Result := Param AND NOT BitMask; А теперь собственно вопрос, в своей программе я использую маски оформив их читабельными именами в константы. Если использовать расчет маски то я могу использовать следующий вариант функции: Function BitSetByFlag(Param, Mask : Byte; Flag : Boolean) : Byte; begin Result := Param OR (Ord(Flag) shl BitNumb); end; Как мне добиться того же результата с уже готовой маской в виде константы? Никак не могу понять... =( Конечно, я могу использовать те же константы для позиций битов, а не маски, но просто интересно как получить сабж. 3) - Имеется некий тип файла со следующей структурой: заголовок(который в данный момент меня интересует) и данные. Заголовок выглядит следующим образом: 2 байта на колл-во параметров, 80 байтов на заголовок, сам список параметров в размере кол-во параметров*8 байтов на каждый и аналогичный расчет для описания как параметр использовать. В описании к формату сказано отдельными командами записать кол-во параметров в файл, записать заголовок(если требуется, иначе забить нулями), записать список параметров. Я попытался объявить тип запись такого вида: THeader = record ParamCount : Word; Caption : String[80]; Parameters, Discription : String; end; Когда записал данную структуру в файл, обнаружил в хекс редакторе, что перед заголовком стоИт байт с колл-вом реально записанных в него символов и только потом сам заголовок, а вместо списка параметров и описателей толи указатели, толи еще что. Записывал через TFileStream. Подскажите пжл, что я сделал не так? Пока что все, спасибо.
|
|
|
Записан
|
|
|
|
Sla
|
|
« Ответ #1 : 19-12-2011 14:05 » |
|
Побольше таких новичков 1) - При использовании подпрограмм во время передачи параметров в них, передается содержимое переменных или только указатель на переменную или там вообще другой принцип? Например объявив процедуру Test(Par : Byte), во время ее вызова ей передается байт информации или просто увеличивается счетчик ссылок на нее? Это я все к обработке больших переменных. Существую параметры-переменные и параметры-значения. Наиболее полный ответ тебе даст листинг ассемблеровского кода. Если просто... Параметр- переменная - ссылка Параметр-значение - зарезервированное место в стеке. Это если очень просто. (т.е. для новичка)
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Sla
|
|
« Ответ #2 : 19-12-2011 14:10 » |
|
Вопрос третий.
На этапе компиляции ты не имеешь понятия о размере записываемого блока. Но тебе нужно записать структуру с переменным количеством байт. Как ты поступишь?
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #3 : 19-12-2011 15:13 » |
|
1) Если параметр процедуры/функции объявлен просто так, то передаётся по значению, если с помощью служебного слова var - по ссылке. procedure P(X: Integer; var Y: Integer); Здесь X передаётся по значению, Y - по ссылке. 2) Я вопроса не понял. Что не работает? 3) Покажи код, который пишет в поток. Вообще, если число параметров переменное, то нужен байтовый файл, а дальше читать/писать в 2 этапа: сначала запись с заголовком, потом переменное количество записей другого типа с параметрами. Есть ещё, правда, типы записей с вариантами (конструкция case внутри record), но они годятся лишь для фиксированного небольшого количества вариантов.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Вад
|
|
« Ответ #4 : 19-12-2011 16:48 » |
|
К первому вопросу хочу добавить, что никаких счётчиков ссылок в Delphi нет. Передача по ссылке просто означает, что копируются не сами данные, а лишь информация об их местонахождении, используемая внутри функции для получения прямого доступа в соответствующую область памяти.
|
|
|
Записан
|
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #5 : 19-12-2011 17:18 » |
|
Спасибо за быстрые ответы. 1) - Т.е. если я хочу передать не содержимое параметра, а ссылку на него, мне просто достаточно добавить Var перед ним? А как тогда насчет классов? Например процедура P(Btn : TButton); в которой я меняю текст кнопки. Получается если я не добавлю Var перед Btn, то внутри процедуры будет создана другая копия кнопки? 2) - Весь смысл вот в этом месте: Result := Param OR ( Ord(Flag) shl BitNumb); Сейчас я как временное решение сделал такую конструкцию: Function BitSetByFlag(Var Param : Byte; Mask : Byte; Flag : Boolean); begin if Flag then Param := Param OR BitMask else Param := Param AND NOT BitMask; end; Но для меня гораздо красивее было бы использовать конструкцию выше. Понятно что лишняя функция Ord() вызывается, а проверка была бы быстрее по времени, зато элегантнее. 3) - Вот создал тестовый хедер, первые 2 байта - кол-во параметров, следующие 4 байта заголовок, далее по 8 байт на каждый параметр и описание: Offset(d) 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
00000000 00 04 04 54 65 73 74 50 61 72 61 6D 30 00 00 50 ...TestParam0..P 00000016 61 72 61 6D 31 00 00 50 61 72 61 6D 32 00 00 50 aram1..Param2..P 00000032 61 72 61 6D 33 00 00 48 6F 77 32 55 73 65 30 48 aram3..How2Use0H 00000048 6F 77 32 55 73 65 31 48 6F 77 32 55 73 65 32 48 ow2Use1How2Use2H 00000064 6F 77 32 55 73 65 33 ow2Use3
Как вы можете наблюдать, третий байт является лишним: 00000000 00 04 04 54 65 73 74 50 61 72 61 6D 30 00 00 50 .. .TestParam0..P В нем содержится колл-во реально записанных в заголовок символов. Если бы я обозвал заголовок Тс, например, то там было бы 02. Как бы мне его выкинуть? Пробовал использовать массив символов Array[1..80] of Char, проблема пропадала, но не совсем с этим массивом удобно работать. Если подскажите как лучше, был бы благодарен. Я использовал заполнение в цикле, но это столько кода лишнего, куда проще ведь FHeader.Caption := 'Some caption'; и все. В общем как-то так. ЗЫ: перечитал оба своих поста, видимо я вас своими заголовками запутал, извиняюсь =)
|
|
« Последнее редактирование: 19-12-2011 17:27 от Karrakurt »
|
Записан
|
|
|
|
Sla
|
|
« Ответ #6 : 19-12-2011 17:34 » |
|
Даже разбираться не хочется - почему там "лишний" байт. Задам вопрос Как представлен в паскале (делфи) тип string?
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #7 : 19-12-2011 17:34 » |
|
Karrakurt,
1) Объекты передаются по указателю. В старом Pascal указатель был явный. В Object Pascal (который в Delphi) указатели на объекты убраны из синтаксиса, чтобы не загромождать код, но остаются указателями. Грубо говоря, любой пользовательский тип class - это тип типизированного указателя.
Из этого следует, что для передачи объекта нет большой разницы между передачей по ссылке или по значению. Передаётся лишь указатель (по значению или ссылке). Если он передан по ссылке, ему можно присвоить другой объект (указатель на другой объект), и это станет видно в вызывающей программе; иначе, если он передан по значению, изменение значения указателя не будет видно в вызывающей программе. Однако с самим объектом, с его внутренностями можно делать всё, что позволяет его интерфейс - это одинаково работает и при передаче по ссылке, и при передаче по значению.
3) Я всё равно не очень понял, что тебе не нравится.
Паскалевская строчка имеет формат: в начале идёт размер строки, потом сама строка - этот формат отличается от сишных строчек, завершаемых нулевым символом.
Если тебе нужны строго 80 символов без начального размера и конечного нуля, то работай не со строкой, а с массивом символов.
|
|
« Последнее редактирование: 19-12-2011 17:44 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Sla
|
|
« Ответ #8 : 19-12-2011 17:43 » |
|
Dimka, эх, попалил... вопрос.
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #9 : 19-12-2011 17:49 » |
|
Karrakurt,
По 2 я вообще не понял, какая связь между твоим решение с Ord и твоим же решение с if. Ord - функция, возвращающая порядковый номер значения перечислимого типа. Для Boolean Ord(False) = 0, Ord(True) = 1, для Char - это ASCII код символа, и т.д. Ноль, конечно, можно битово двигать влево, если так хочется, но будет по-прежнему ноль, и сложение с нулём даёт оригинальное число.
Никаким образом при помощи Ord нельзя получить инвертирование битов, которое ты хочешь в конструкции and not.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #10 : 20-12-2011 12:51 » |
|
Ну чтож, по первому вопросу вроде бы все понятно, спасибо. По поводу второго. 2 DimkaДа, Вы правы, этот способ не работает, видимо когда писал представленную конструкцию не проверил все варианты. Сегодня, наверное, битый час решал эту битову математику, в итоге родил следующее: Function _BitSetByFlag(Source : Byte; Index : Byte; Flag : Boolean) : Byte; begin Result := (Source AND NOT (1 shl Index)) OR (Ord(Flag) shl Index); end; Все что получалось другим путем, требовало преобразования типов, дополнительных переменных и манипуляций, что в итоге было нецелесообразно. В конечном счете остановился на варианте с if, хотя, если у кого есть какие-либо предложения, с радостью поучусь. Пока вопрос решен. Dimka, эх, попалил... вопрос.
Глумитесь? =) Ну кто ж знал что при записи сохраняется и внутренняя структура переменной, да и со способом хранения строки я не очень в курсе был. Но ведь это не просто строка, а короткая строка, не? В общем, пока поищу инфу по строкам и массивам символов, а ежели у кого будут предложения как лучше мне поступить, очень прошу не молчать, спасибо всем за ответы.
|
|
« Последнее редактирование: 22-12-2011 11:55 от Karrakurt »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #11 : 20-12-2011 15:38 » |
|
очень прошу не молчать Я бы написал процедуру, которая записывает произвольную строку в произвольную позицию файла байтов как массив символов указанной длинны. Процедура же должна обрабатывать случаи, когда строка короче поля (надо ли забивать нулями пустые позиции или нет), когда строка длиннее поля (надо обрезать или генерировать исключительную ситуацию). Имея такую замечательную процедуру, я бы ей дальше вовсю пользовался. если у кого есть какие-либо предложения, с радостью поучусь. Если ты считаешь, что запись в одну строку - это лучше, чем в несколько, то такое мнение нужно чем-то мотивировать. BitMask := 1 shl BitIndex; if BitIsSet then Result := Source or BitMask else Result := Source and not BitMask; У этого решения есть то очевидное достоинство, что всякому, имеющему представление о работе с битами, с первого взгляда совершенно понятно, что именно здесь делается. В каком-нибудь C-образом языке это можно записать в две строчки bitMask = 1 << bitIndex; result = bitIsSet ? source | bitMask : source & ~bitMask; Никаких преимуществ при выполнении эта запись не несёт. Читабельность её, на мой взгляд, хуже, поскольку выходит длинное выражение. Можно укротить и до одной строчки: result = bitIsSet ? source | (1 << bitIndex) : source & ~(1 << bitIndex); Конечно, умный компилятор это соптимизирует таким образом, чтобы два раза не вычислять один и тот же битовый сдвиг, а неумный компилятор ухудшит машинное решение по сравнению с исходным. Читабельность ещё сильнее упала за счёт повышения нагромождений. Многократно используемая переменная с хорошим (адекватным задаче) названием - BitMask - резко повышает понятность алгоритма. Переменная с весьма абстрактным и непонятно как относящимся к делу названием - Flag - не облегчает жизнь программиста. Теперь о чисто математическом подходе. В вышеприведённых решениях везде наличествует выбор по условию, переключающему исполнителя со схемы or на схему and not. Очевидно, что для записи в одну строчку исходное выражение должно быть подвергнуто такому преобразованию, чтобы в его основе для любого варианта оставалось какое-то одно общее выражение, например or, а другой вариант реализовывался бы как опциональная надстройка над исходным выражением. Если за основу выбрать простое x | y, то более сложное x & ~y нужно преобразовать к |. Нетрудно догадаться, что x & ~y - это отрицание импликации, следовательно, эквивалентное ему выражение через | будет выглядеть как ~(~x | y). В этом случае упомянутыми опциями будут отрицание x и отрицание всего выражения. Это по сути дела одна опция, применённая 2 раза, и она должна включаться и выключаться в зависимости от потребности. Тогда исходная задача сводится к такой: какое выражение будет эквивалентно следующему: c ? x : ~x При помощи исключающего или x можно вообще вынести за скобку, и тогда вся опция превратится в самостоятельный оператор, поведение которого настраивается при помощи переменной c: (c ? 0 : ~0) ^ x оператор здесь - это выражение (c ? 0 : ~0) ^ переменная, к которой применяется этот унарный оператор - x. Тогда мы уже можем записать временное решение в 2 строчки: BitMask := 1 shl BitIndex; {Начало временного решения} if BitIsSet then Condition := 0 else Condition := not 0; {Конец временного решения} Result := Condition xor ((Condition xor Source) or BitMask); Остаётся вопрос о том, как преобразовать значение Boolean в целочисленное значение, у которого все биты либо сброшены в 0, либо установлены в 1. Одним из решений является переход к внутреннему формату хранения Boolean-значений. Этот хакерский вариант, зависящий от реализации компилятора языка и целевой аппаратной платформы, я считаю недостойным и уж тем более не математическим. Использование функции Ord - более легальный вариант, независимый от аппаратной платформы. С помощью функции Ord из Boolean-значения мы получим число либо 0, либо 1. Если 0 замечательно соответствует 0, то 1 никак не соответствует not 0, и нужно придумать выражение, которое бы делало такое преобразование. Опять же хакерский вариант может быть основан на том факте, что в ряде систем not 0 = -1, тогда искомое выражение превращается в: Result := -Ord(not BitIsSet) xor ((-Ord(not BitIsSet) xor Source) or (1 shl BitIndex)); И ещё важно смотреть на размеры типов. В старом Pascal Ord возвращает значение типа LongInt - целое число максимального размера, так что вроде бы не должно возникать ситуации, когда инвертируется лишь правая часть битов. Однако это выражение совершенно нечитабельно по сравнению с оригиналом - непонятно, что оно делает и основано на хакерстве - опирается на особенности аппаратного представления типов данных. Таким образом, проигрывает исходному варианту. Заметь, что своими попытками комбинировать and и or ты бы никогда не пришёл к такому правильному результату - он слишком сложен, неочевиден. P.S. Из этих рассуждений, кстати, хорошо видно, почему в 2D компьютерной графике и анимации так любят операцию xor и чёрно-белые маски.
|
|
« Последнее редактирование: 20-12-2011 21:59 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #12 : 22-12-2011 11:42 » |
|
2 Dimka Спасибо за ответ, практически целый урок вышел.
В общем по первым 2-ум вопросам все ясно, а по третьему вы советуете не создавать запись, как я предлагал выше, а писать все в файл поочередно? Или, например, можно объявить переменную типа Array of Byte и поочередно записать все в нее, а потом ее записать в файл?
|
|
|
Записан
|
|
|
|
Sla
|
|
« Ответ #13 : 22-12-2011 12:02 » |
|
2 Dimka Са по третьему вы советуете не создавать запись, как я предлагал выше, а писать все в файл поочередно? Или, например, можно объявить переменную типа Array of Byte и поочередно записать все в нее, а потом ее записать в файл?
С чем боремся?
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #14 : 22-12-2011 12:17 » |
|
С чем боремся?
Боремся с выбором более правильного алгоритма. Варианты: 1) - Как я сразу предложил создать тип запись, описанную выше, но если использовать тип String, то будет лишний байт. Если использовать массивы символов, то типы Array[0..79] of Char и Array of Char считаются ведь разными? Тогда нужно создавать их всех в виде TCharArr = Array of Char и определять размер перед заполнением, что в общем-то не проблема и далее писать в файл. 2) - Камрад Dimka предложил писать заголовок сразу в файл написав процедурку для этого. 3) - Дабы не писать несколько раз один заголовок, можно объявить переменную типа массива байт, поместить в нее всю инфу и записать один раз весь заголовок. Вот собственно с этим и боремся =) Я пока не имею достаточного опыта работы ни по одному из этих вариантов, потому и спрашиваю.
|
|
|
Записан
|
|
|
|
Sla
|
|
« Ответ #15 : 22-12-2011 12:38 » |
|
Я не понимаю... почему Вы считаете, что лишний? Вам объяснили почему он не лишний
Вы самостоятельно хотите парсить файл данных объявив его type of byte?
Записали records Прочитали records. И никакой головной боли у программиста. Система, вернее, компилятор+библиотеки самостоятельно разрулят ситуацию
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #16 : 22-12-2011 13:26 » |
|
Karrakurt, нельзя создать тип переменного размера. Из этого обстоятельства и вытекает алгоритм работы с файлом. И я нигде не предлагал записывать запись в байтовый массив - лишь в байтовый (нетипизированный) файл. Для этого замечательно подходят функции BlockRead и BlockWrite, позволяющие объект произвольного типа записать в файл как последовательность байтов или прочитать из файла последовательность байтов в тот участок памяти, в котором размещён объект нужного типа. Про байтовый массив я говорил лишь в контексте типа string. Вы самостоятельно хотите парсить файл данных объявив его type of byte? Нет, он просто не понял, зачем ему байтовый файл. Но знания того, какие записи в каком порядке и количестве записаны в такой файл, ему не избежать.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #17 : 17-03-2012 18:21 » |
|
Приветствую всех, еще пара вопросов. Можно ли как-то создавать дубликаты контролов? Т.е. имеется например панель, которая в процессе работы меняет, ну например цвет и капшн. Имеется прога, которая запускается на двух мониторах, и на каждом мониторе разный набор элементов, но панель должна быть и тут и там. Так вот можно ли сделать так, чтобы менять ее состояние приходилось только в одном месте, а реально менялось в двух? И вытекающий из вышеперечисленного вопрос, можно ли создать класс, в нем объявить переменную панель, а далее из основной программы, не знаю, присвоить эту "классовую" панель нужным мне панелям? Наверное все запутанно, но как-то так... =)
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #18 : 17-03-2012 20:09 » |
|
Karrakurt, если на двух мониторах одно и то же изображение, то вопрос смысла не имеет. Если на двух мониторах "длинный" рабочий стол, то на каждом мониторе будет своё собственное окно, и все контролы и панели будут иметь по 2 независимых друг от друга экземпляра.
Надеюсь, разницу между классом и экземпляром контрола ты понимаешь.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #19 : 18-03-2012 11:39 » |
|
Dimka, а я почему-то считал, что длинный рабстол аппаратно делится на два изображения (на два монитора), а на самом деле окно одно. Это разве не так ?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #20 : 18-03-2012 14:03 » |
|
Алексей1153++, касаемо рабочего стола - не вполне. Хотя бы потому, что панель задач присутствует лишь на одном мониторе, и на разные мониторы можно вывести разные обои. Но с точки зрения окон приложений такой рабочий стол - это единое пространство, и окно можно поместить так, что часть окна будет на одном мониторе, а другая часть - на другом. Однако попытка сделать full screen к успеху не приведёт: full screen будет только на одном мониторе - на том же, где панель задач, на том, который считается основным. Но я не понял твоего " а я почему-то считал..." Потому что о свойствах рабочего стола я не говорил Я лишь сказал, что пожелание автора темы реализуется с помощью двух окон на "длинном" рабочем столе.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Karrakurt
Участник
Offline
|
|
« Ответ #21 : 18-03-2012 19:34 » |
|
Так значит никак не получится сделать два идентичных контрола "зависимыми" друг от друга и в любом случае придется обрабатывать их по отдельности?
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #22 : 18-03-2012 19:56 » |
|
Ну можно сделать механизм синхронизации.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #23 : 19-03-2012 05:18 » |
|
Dimka, понятно. Это я пропустил момент про два контрола
я сам с двумя мониторами пока не сталкивался
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #24 : 19-03-2012 05:34 » |
|
Karrakurt, обратись к архитектуре MVC. На одну модель сделай 2 представления.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
|