purebasic.info

PureBasic forum
Текущее время: Сб июн 23, 2018 9:09 am

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 15 ] 
Автор Сообщение
 Заголовок сообщения: Великие и ужасные процедуры
СообщениеДобавлено: Чт дек 18, 2008 1:12 am 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Сб авг 18, 2007 6:26 pm
Сообщений: 605
Откуда: Северодвинск/Питер
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Я вот подумал, и решил, что стоит вынести обсуждение этой мощной конструкции(в данном случае, я не только о Пурике, а вообще о функциях =) ) Хотелось бы поделиться своими "открытиями"(кое-чего в хэлпе почему-то нет O_o)

Итак, поехали!

Начну с того, что процедура отлично может принимать указатели(совет скорее новичкам, профессионалы могут работать с памятью и без указателей :) ), что дает возможность не только передавать указатели на структуры, связанные списки и массивы(для последних двух и так есть встроенные средства передачи, реализация та же, но обертка другая, об этом позже :D ), но и изменять значение передающейся в качестве парамерта переменной(в том числе и большой структуры; Так вы можете возвращать не 1 число командой ProcedureReturn, а хоть 100 =) )
Код:
1
2
3
4
5
6
7
8
9
 
Procedure Test(*Variable.LONG)
  *Variable\l=*Variable\l*2
EndProcedure
 
Var.l=10
Test(@Var)
Debug Var
 


К сожалению, "*" перед переменной стандартного типа(.l, к примеру) не делает её указателем на переменную, поэтому пример получился ненаглядным(например, многие могут не понять, почему это используется какая-то левая структура LONG. Попробую пояснить: * перед переменной структуры делает переменную именно указателем, поэтому приходится прибегать к извращению - делать(в данном случае, юзать готовую =) ) структуру с единственным элементом данного типа внутри только для того чтобы PureBasic понял, что это - указатель. Да, сказано сложновато... :oops: )

Следующее. Передача структуры(фактически, то же самое что предудущий пример, но демонстрирующий другие действия)

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
Structure Struct
  A.l
  B.l
  C.s
EndStructure
 
 
Procedure Test(*Variable.Struct)
  Debug *Variable\A ;Показываем, что было в поле A
  Debug *Variable\B ;Показываем, что было в поле B
  Debug *Variable\C ;Показываем, что было в поле C
 
  *Variable\A=*Variable\A+10 ; И так можно, изменится не только то что в процедуре, но и внешняя переменная Var, так как работа - через указатель
EndProcedure
 
Var.Struct
Var\A=100
Var\B=321
Var\C="Тестовая строка"
 
Test(@Var)
 



Далее. Передача массивов и связанных списков. Для этого в PureBasic предусмотрен стандартный способ -в качестве параметра функции вы пишете название формального массива внутри процедуры, его тип и в скобочках - размерность(1 - одномерный, 2- двухмерный и тд. Как PureBasic умудряется определять, как именно расположены данные в произвольном массиве - я не знаю, но он это делает. То есть объявили вы массив Dim Array(10,20) - в структуре он будет принят и прочитан совершенно аналогично, хотя по идее должны бы перепутаться поля, обычно в массивах не хранится информация о конце столбца...)
Пример:

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
Structure Struct
  A.l
  B.l
  C.s
EndStructure
 
 
Procedure Test(Array.Struct(2),M,N)
  Protected S.s
 
  For I=0 To M-1
    S=""
    For J=0 To N-1
      S+RSet(Str(Array(I,J)\A),2,"0") +" "
    Next
    Debug S
  Next
EndProcedure
 
Dim MyTestArray.Struct(5,10)
 
For X=0 To 4
  For Y=0 To 9
    MyTestArray(X,Y)\A=X+10*Y
  Next
Next
 
Test(@MyTestArray(),5,10)
 


Замечу также, что на самом деле массив в процедуру не передается, передается только указатель, а отсюда следует, что при изменении массива внутри процедуры он изменится и вне процедуры.

Со связанными списками ситуация та же, что и с массивами, за исключением того что в скобках не указывается размерность =) Пример приводить не буду, но замечу, что, если вы сделали AddElement() с формальным списком(внутри функции), элемент появится и в основном списке, то же касается и любых других изменений, от выбора нового элемента до изменения элементов списка :roll:

Есть ещё одна любопытная вещь, которую я заметил буквально вчера. До сих пор не разобрался, что с ней можно делать, но всё же:

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
Structure Struct
  A.l
  B.l
  C.l
EndStructure
 
 
Procedure Test(Var.Struct\A)
  Var\B=20
  Var\C=30
 
  Debug Var\A
  Debug Var\B
  Debug Var\C
 
EndProcedure
 
 
Test(10)
 


Судя по всему, это - баг, и использовать его категорически не рекомендуется!!! Параметр пишется в любом случае только в первое поле структуры, память для остальных вообще не выделяется! Для подобного рода передач лучше использовать указатели.


Ну и ещё, в качестве бонуса, довольно полезная вещь - конструктор для заданного типа(тоже упрощает передачу структуры в функции =) ):

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
Structure Vector
  X.f
  Y.f
  Z.f
EndStructure
 
Procedure Vector(X.f,Y.f,Z.f)
  Protected *Var.Vector = AllocateMemory(SizeOf(Vector))
 
  *Var\X=X
  *Var\Y=Y
  *Var\Z=Z
 
  ProcedureReturn *Var
EndProcedure
 
Procedure.f VecLen(*Vector.vector)
  ProcedureReturn Sqr(*Vector\X**Vector\X+*Vector\Y**Vector\Y+*Vector\Z**Vector\Z)
EndProcedure
 
 
;Подход с конструктором:
*Vector.vector=Vector(10,20,30)
Debug VecLen(*Vector)
FreeMemory(*Vector)
 
;Классический подход:
Var.Vector
Var\X=10
Var\Y=20
Var\Z=30
Debug VecLen(Var)
 


Я немного усложнил код примера с улучшенным подходом по настоянию Lnk'а, так как, если периодически использовать конструктор, не убирая память после использования, вся оперативная память будет забита, эта ошибка называется "утечка памяти" :oops:

ЗЫ: надеюсь, информация пригодится, в принципе, ничего особенного, но на то и Tips&Tricks 8)

_________________
http://www.youtube.com/watch?v=XHosLhPEN3k


Последний раз редактировалось All_Creater Чт дек 18, 2008 7:56 pm, всего редактировалось 1 раз.

Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 18, 2008 2:06 am 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Пн ноя 27, 2006 2:43 pm
Сообщений: 931
Откуда: Санкт-Петербург
Благодарил (а): 1 раз.
Поблагодарили: 12 раз.
Пункты репутации: 15
спасибо
думаю в ответ на многие вопросы можно будет адресовать сюда


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 18, 2008 4:18 pm 
Не в сети
доцент

Зарегистрирован: Ср окт 15, 2008 2:35 pm
Сообщений: 42
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Цитата:
Есть ещё одна любопытная вещь, которую я заметил буквально вчера. До сих пор не разобрался, что с ней можно делать, но всё же:
Код:

Structure Struct
A.l
B.l
C.l
EndStructure


Procedure Test(Var.Struct\A)
Var\B=20
Var\C=30

Debug Var\A
Debug Var\B
Debug Var\C

EndProcedure


Test(10)

Переданное в процедуру число записывается в начало структуры, в данном случае в поле А. Если объявить процедуру Procedure Test(Var.Struct\В), то результат будет тем же самым.
Все аргументы процедуры - те же самые локальные переменные, начальные значения которых передаются при вызове процедуры. Так что нет ничего удивительного в том, что в переменную Var попало число 10, а именно в поле А. Но это потому, что их размерности совпали (32 бита). Такое поведение следует рассматривать как баг PB. Надеюсь в будущем он будет устранен - компилятор не допустит такого синтаксиса, так как нелогично указывать в типе параметра поле структуры.
Но и это еще не все. Закомментируй строки
Var\B=20
Var\C=30
и запусти программу. Первые четыре байта (поле А) были инициализированы, а остальные - нет! Это само по себе очень опасно, тем более, что концепция PB подразумевает обязательную инициализацию всех переменных (в отличие от С).

Цитата:
Structure RGB
StructureUnion
Color.l
Comp.b[4]
EndStructureUnion
EndStructure


Procedure Test(Var.RGB\Color)
Debug Var\Comp[0] & 255
Debug Var\Comp[1] & 255
Debug Var\Comp[2] & 255
Debug Var\Comp[3] & 255
EndProcedure


Test(RGB(255,128,64))

Здесь можно благополучно обойтись без процедуры:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Structure RGB 
  StructureUnion
    Color.l
    Comp.b[4]
  EndStructureUnion
EndStructure
 
Define Var.RGB
 
Var\Color=RGB(255,128,64)
Debug Var\Comp[0] & 255
Debug Var\Comp[1] & 255
Debug Var\Comp[2] & 255
Debug Var\Comp[3] & 255


Единственная разница, что у тебя переменная типа RGB объявлялась как локальная в процедуре.

А вот за следующий код надо расстреливать на месте.
Цитата:
Structure Vector
X.f
Y.f
Z.f
EndStructure

Procedure Vector(X.f,Y.f,Z.f)
Protected *Var.Vector = AllocateMemory(SizeOf(Vector))

*Var\X=X
*Var\Y=Y
*Var\Z=Z

ProcedureReturn *Var
EndProcedure

Procedure.f VecLen(*Vector.vector)
ProcedureReturn Sqr(*Vector\X**Vector\X+*Vector\Y**Vector\Y+*Vector\Z**Vector\Z)
EndProcedure


;Подход с конструктором:
Debug VecLen(Vector(10,20,30))

Где освобождение памяти??? Вот так вот и создаются программы, после которых все тормозить начинает!
Правильный вариант:
Код:
1
2
3
4
5
 
*vect = Vector(10,20,30)
Debug VecLen(*vect)
FreeMemory(*vect)
 



Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 18, 2008 7:51 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Сб авг 18, 2007 6:26 pm
Сообщений: 605
Откуда: Северодвинск/Питер
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Lnk писал(а):
Переданное в процедуру число записывается в начало структуры, в данном случае в поле А. Если объявить процедуру Procedure Test(Var.Struct\В), то результат будет тем же самым.
Все аргументы процедуры - те же самые локальные переменные, начальные значения которых передаются при вызове процедуры. Так что нет ничего удивительного в том, что в переменную Var попало число 10, а именно в поле А. Но это потому, что их размерности совпали (32 бита). Такое поведение следует рассматривать как баг PB. Надеюсь в будущем он будет устранен - компилятор не допустит такого синтаксиса, так как нелогично указывать в типе параметра поле структуры.

Да, я обратил внимание, что остальные поля структуры не инициализируются =( А вот того, что пишется всегда только в первое поле - не знал. Спасибо за пояснение, выходит, юзать ЭТО не стоит.

Lnk писал(а):
Здесь можно благополучно обойтись без процедуры:
Код:
Structure RGB
StructureUnion
Color.l
Comp.b[4]
EndStructureUnion
EndStructure

Define Var.RGB

Var\Color=RGB(255,128,64)
Debug Var\Comp[0] & 255
Debug Var\Comp[1] & 255
Debug Var\Comp[2] & 255
Debug Var\Comp[3] & 255

При желании можно упростить всё что угодно :P , я просто привел пример использования фичи, которая, как выяснилось, есть баг =)Сейчас как раз подкорректирую примеры.

Lnk писал(а):
А вот за следующий код надо расстреливать на месте.

А вот и нет :P. Про утечку памяти я не сказал, да, и полностью поддерживаю твой код. Тем не менее, Пурик всё равно освободит память после выхода из проги(специально смотрел, написано ли это про AllocateMemory, выяснилось, что написано.), а пару раз можно и создать и новый экземпляр :roll:

_________________
http://www.youtube.com/watch?v=XHosLhPEN3k


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 12:42 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Ребята, у меня тут затык(

Передаю в процедуру указатель на структуру, там её инициализирую, но если в строковый элемент структуры записываю больше данных чем там было происходит ошибка памяти(


Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
Structure test
string.s
EndStructure
 
Define test.test
 
Procedure StrTest(*test.test)
 
Debug *test\string
*test\string="###"
Debug *test\string
*test\string="%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
Debug *test\string
 
EndProcedure
 
test\string="***"
 
StrTest(@test)
 
Debug test\string
 



Пример работает в обычных условиях, но у меня unicode и процедура находится в DLL библиотеке и вызывается посредством CallFunctionFast(strtest, @test)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 1:14 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11188
Благодарил (а): 4 раз.
Поблагодарили: 416 раз.
В DLL нельзя подобное делать, т. к. используются разные источники памяти под строки.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 1:24 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
как тогда быть? сейчас планируется много текста в структуре возвращать из длл...
можно конечно для каждого элемента выделять память, но не хочется ибо придется очень много переделывать( там не реально большой проект.

Вообще в нем во всех ДЛЛ читаются строки из структуры, но ни когда в эту структуру ни чего строкового не пишется, а вот сейчас приспичило...


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 1:38 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
еще кое что: указатель на строку в структуре остается одинаков, и после записи в нее тоже, в основном потоке и в ДДЛках... баг видимо заключается в том что при превышении объема запись ведется поперек прочих элементов структуры, или чего-то близлежащего к локации этой строки...

может как-то переназначить указатель на строку в структуре на уже обновленную строку

типа *test\string=@string$


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 2:39 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Чт дек 17, 2009 4:49 pm
Сообщений: 1230
Откуда: г. Ангарск
Благодарил (а): 2 раз.
Поблагодарили: 15 раз.
Пункты репутации: 10
tester112
В передаваемой структуре, храни не строку, а указатель на строку. Если и так непрокатит, то создавай новую структурированную переменную(переписывай в неё все значения) и её адрес возвращай через ProcedureReturn.

_________________
.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 2:49 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
lakomet - Спасибо в крайнем случае так и сделаю...
оцениваю масштабы: в одной только структуре 29 строковых, всего 15 ДЛЛ (1500-8000 строк кода) все они активно юзают эту структуру... боюсь у мну руки отвалятся(


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 2:53 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11188
Благодарил (а): 4 раз.
Поблагодарили: 416 раз.
http://www.purebasic.fr/english/viewtop ... 13&t=55730

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 3:44 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Перепроверил, в действительности указатели на строковые элементы структуры отличаются в основном потоке и в ДЛЛ.

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

Так я понимаю:
Код:
1
2
string$="***"
*test\string=@srting$



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 3:46 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11188
Благодарил (а): 4 раз.
Поблагодарили: 416 раз.
Если максимальная длина строк заранее известна, то можно использовать строки фиксированной длины. Они располагаются непосредственно в структуре и все должно работать нормально.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 3:53 pm 
Не в сети
доцент

Зарегистрирован: Вт июл 07, 2009 1:17 pm
Сообщений: 25
Благодарил (а): 3 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
надо попробовать, у половины элементов думаю можно определить размерность

а как в данном случае механизм PureBasic'а поведет себя при превышении размера?
урежет записываемую строку или запишет как получится с глюками?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Великие и ужасные процедуры
СообщениеДобавлено: Пн фев 03, 2014 3:57 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11188
Благодарил (а): 4 раз.
Поблагодарили: 416 раз.
Урежет строку при превышении ее длины.
Код:
1
2
3
4
5
6
7
8
9
10
11
12
Structure x
  x.l
  str.s{4}
  y.l
EndStructure
x.x\x=-1
x\y=-1
x\str="PureBasic"
ShowMemoryViewer(@x, SizeOf(x))
Debug x\x
Debug x\str
Debug x\y


_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 15 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


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

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB