FreeBasic
Вы хотите отреагировать на этот пост ? Создайте аккаунт всего в несколько кликов или войдите на форум.

передача аргументов в процедуры и функции

Участников: 3

Перейти вниз

передача аргументов в процедуры и функции Empty передача аргументов в процедуры и функции

Сообщение  Eric-S Пт Авг 22, 2008 8:58 am

Глава о том как передать данные в функцию и что с этим можно будет сделать дальше.

В этой главе, под словом "процедура" понимаються любые из конструкций
function ... end function функции
sub ... end sub процедуры
property ... end property
constructor ... end constructor
Так будет проще, чтобы не перечислять их каждый раз. Ведь правила передачи аргументов для них одинаковые.

Передаваемые аргументы могут быть любого типа. Их набор может быть фиксирован или же произволен.


Код:

' передача параметра

' тестовая процедура
sub foot( a as integer, b as integer )

' первый аргумент
print "a = "; a

' второй аргумент
print "b = "; b
end sub

' вызываем процедуру с параметрами
foot 5, 8


В строке 2, где объявляется наша процедура, в круглых скобочках указываем имя аргументов и тип данных.
Код:

sub foot( a as integer, b as integer )

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

Код:

' пример передачи переменной

' тестовая процедура
sub foot( a as integer, b as integer )

' первый аргумент
print "a = "; a

' второй аргумент
print "b = "; b
end sub

' переменные
dim p1 as integer = 123
dim p2 as integer = 456

' вызываем процедуру с параметрами
foot p1, p2


Не имеет значения , что мы передаём переменную с именем "p1" или "p2", в процедуре к ней надо будет всё равно обращаться, по имени, которое указано при описании этой процедуры.
В нашем случае это "a" и "b".



byRef и byVal [/i]

Аргументы можно передать двумя способами, по ссылке или значению. КАкой способ используется по умолчанию зависит от настроек. По сему рекомендую задавать его в обязательном порядке.
Делается это с помощью ключевых слов

byVal - по значению

byRef - по ссылке


Разница заключается в том, что byVal, копирует значение в аргумент. В процедуре или функции вы можете изменять его, но на оригинальную переменную это не повлеяет.

А указав byRef мы берём ссылку на оригинальное значение. Изменяя значения аргумента, вы изменяете значение параметра.

Вот посмотрите пример
Код:

' тестовая процедура
sub foot( byVal a as integer, byRef b as integer )

' первый аргумент
print "a = "; a

' второй аргумент
print "b = "; b

' обнуляем оба аргумента
a = 0
b = 0
end sub

' переменные
dim p1 as integer = 123
dim p2 as integer = 456

' напечатаем переменные до вызова процедуры
print p1, p2

' вызываем процедуру с параметрами
foot p1, p2

' напечатаем переменные после процедуры
print p1, p2


Программа вернёт

123 456
a = 123
b = 456
123 0

Как видим, с оригинальным значением p1 ничего не случилось. Оно было 123. А то что в процедуре аргумент был изменён, на оригинальное значение не повлеяло.

Значение переменной p2 456, передавалось по ссылке. Оно было изменено в процедуре.
По этому, после завершения процедуры переменная p2 уже содержит 0.





[b] передача массива в функцию


Массив передаётся только по ссылке. Обязательно нужно указать пустые круглые скобочки. после имени массива. Указывать ключевые слова byVal и byRef не допускаеться.


Код:
 ' передача массива

' создадим массив
dim a(1 to 10) as integer
a(10) = 1000

function myfunc3(b() as integer) as integer
print b(10)
b(1) = 111
b(2) = 222
b(3) = 333
end function

myfunc3( a() )

' выведем все значения массива
dim i as integer
for i = 1 to 10
print a(i)
next

sleep


передача указателей

Вы думаете указатели будут обрабатыватся по особенному. Ну зачем же такие сложности. Указатель это переменная с каким-то значением и только.

указатель передаётся точно так же, как из правой части в левую при присвоении. Если вам будет легче, считайте его как число uinteger.


сколько допустимо аргументов

В функцию могут передаваться несколько аргументов. Сколько вы запросите при объявлении функции, столько и будет.

Можно вообще не принимать аргументов. Просто укажите пустые скобочки после имени функции.


Код:

function myfunc0() as integer
end function


Если же несколько аргументов, то их нужно перечислить через запятую.

Код:

function fTrio( a as integer, b as integer, c as integer ) as integer
end function

Эта функция требует 3 аргумента. При её вызове ей нужно передавать 3 параметра. Не больше и не меньше. Это обязательно!

Код:

fTrio( 1, 2, 3 )

Параметры также, перечесляем через запятую.

Существует возможность передавать неопределённое число аргументов, но об этом поговорим дальше.



аргумент по умолчанию

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

Код:
 ' функция печатает имя и фамилию.

function fullName( FirstName as string, lastName as string, poryadok as integer = 0) as integer

if poryadok = 0 then
' в правильном порядке (вариант по умолчанию)
print firstName + " " + lastName
else
' если требуеться другой порядок
print lastName + " " + firstName
end if

return 0
end function

FullName("Ivan", "Ivanovich", 0) ' вывести в правильном порядке
fullName("Mihail", "Sergeevich") ' третий параметр (0), подразумеваеться, но не указываеться, а вообще он не важен
fullName("Vasya", "Pupkin", 1) ' вывести задом наперёд

В этом примере третий аргумент (poryadok) являеться не обязательным. Мы задали его значение по умолчанию. Если параметр был опущен, то аргумент примет значение по умолчанию.
Значение по умолчанию указываеться после знака равенства.
function fulName( poryadok as integer = 0)

Обратите внимание, на то что аргументы со значением по умолчанию должны быть с права, а аргументы без с лева. Иначе будет ошибка.




переменное число аргументов

У функции может быть переменное число аргументов.

Код:

Function FOO cdecl (X As Integer, ...) As Integer
end function

Переменное число аргументов разрешено только для функций cdecl .
Первым аргументом должно быть обычное значение. С помощью него можно указать сколько других аргументов передано в функцию.

Инициировать нужно с помощю функции va_first

Получаем аргумент с помощью va_arg

перейти к следующему аргументу va_next

Код:

Function Avg cdecl (Count As Integer, ... ) As Double
    Dim ARG As Any Ptr
    Dim SUM As Double = 0
    Dim i As Integer

    ARG = va_first()

    For i = 1 To COUNT
        SUM += va_arg(ARG, Double)
        ARG = va_next(ARG,Double)
    Next i
    Return SUM/COUNT
End Function

Print AVG (4, 3.4,5.0,3.2,4.1)
Print AVG (2, 65.2,454.65481)

будет выведено:
3.925
259.927405

Большинство языков высокого уровня передают параметры вызываемой процедуре в стеке и ожидают возвращения параметров в регистре AX (EAX). иногда используется DX:AX (EDX:EAX), если результат не умещается в одном регистре и ST(0), если результат - число с плавающей запятой.

Конвенция Pascal

Самый очевидный способ вызова процедуры или функции языка высокого уровня, после того как решено, что параметры передаются в стеке и возвращаются в регистре AX/EAX, - это способ, принятый в языке Pascal, - просто поместить параметры в стек в естественном порядке:

запись
some_proc(a, b, c, d, e)

превращается в:

push a
push b
push c
push d
push e

Это означает, что процедура some_proc, во-первых, должна очистить стэк по окончании работы (например, завершившиськомандой ret 10) и, во-вторых, параметры, переданные ей, находятся в стэке в обратном порядке:

some_proc proc
push bp
mov bp, sp ; создать стековый кадр
a equ [bp+12] ; определения для простогодоступа к параметрам
b equ [bp+10]
c equ [bp+8]
d equ [bp+6]
e equ [bp+4]
[текст процедуры, использующей параметры a, b, c, d, e]
pop bp
ret 10
some_proc endp

Главный недостаток этого подхода заключается в сложности создания функции с изменяемым числом параметров. Чтобы определить число параметров, процедура должна сначала прочитать первый параметр, но она не знает его расположения в стэке. Эту проблему решает подход, используемый в C, где параметры передаются в обратном порядке.

Конвенция C

Данный способ передачи параметровиспользуется в первую очередь в языках C и C++. Параметры помещаются в стек в обратном порядке, а удаление из стека (в противоположность Pascal-конвенции) выполняет вызывающая процедура:

запись
some_proc(a, b, c, d, e)

превращается в:

push e
push d
push c
push b
push a
call some_proc
add sp, 10 ; освободить стек

Вызванная процедура может инициализироваться следующим образом:

some_proc proc
push bp
mov bp, sp ; создать стековый кадр
a equ [bp+4] ; определения для простого доступа к параметрам
b equ [bp+6]
c equ [bp+8]
d equ [bp+10]
e equ [bp+12]
[текст процедуры, использующей параметры a, b, c, d, e]
pop bp
ret
some_proc endp

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

push param1
push param2
call proc1
call proc2
add sp, 4

эквивалентно

proc1(param1, param2);
proc2(param1, param2);

вот почему компиляторы с языка C создают более компактный и быстрый код нежели компиляторы с других языков.

Смешанные конвенции

Существует также конвенция STDCALL, отличающаяся и от C, и от PASCAL-конвенций, которая применяется для всех системных функций Win32 API. Здесь параметры помещаются в стект в обратном порядке, как в C, но процедуры должны очищать стек сами, как в PASCAL.

Искажение имён

Компиляторы Microsoft C (а также многие компиляторы UNIX), изменяют названия процедур, чтобы отразить используемый способ передачи параметров. Так, к названиям всех процедур, применяющих C-конвенцию, добавляется символ подчёркивания. То есть, если в C-программе записано

some_proc();

то реально компилятор пишет

call _some_proc

и это означает: если процедура написана на ассемблере, она должна называться именно _some_proc.
Названия процедур, использующих STDCALL, искажаются ещё более сложным образом: слева к названию процедуры добавляется символ подчёркивания, а сзади — сивол @ и размер области стека в байтах, которую занимают параметры (то есть число, стоящее после команды ret в конце процедуры)

some_proc(a:word);

превращается в

push a
call _some_proc@4


см. также:
процедуры, функции и свойства
возвращение данных из функции
область видимости


Последний раз редактировалось: Eric-S (Вт Сен 08, 2009 5:16 pm), всего редактировалось 5 раз(а)

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 40
Откуда : Россия, Санкт-Петербург

http://eric50.narod.ru

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Re: передача аргументов в процедуры и функции

Сообщение  Eric-S Пт Авг 22, 2008 11:09 am

Ещё раз, спасибо, за критику, главу исправил.

О скобках. Первые три примера, компилятор не ругался. Всё нормально откомпилировал.

Возможно, что он будет ругаться если в функции есть return?

А кстати, как функции задать пустое значение для возвращения. Это как void в c?

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 40
Откуда : Россия, Санкт-Петербург

http://eric50.narod.ru

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Re: передача аргументов в процедуры и функции

Сообщение  tux Вс Авг 24, 2008 8:28 am

Использовать всместо функции процедуру. Весь смысл в том, что в Си-шке вообще нет процедур, их роль выполняют функции с возвращаемым параметром void
tux
tux

Сообщения : 365
Дата регистрации : 2008-04-06
Возраст : 36
Откуда : Сибирь

http://tux.nsk.ru/

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Re: передача аргументов в процедуры и функции

Сообщение  Eric-S Вс Авг 24, 2008 9:28 am

Я знаю.
Тоесть когда я буду к c подключать библиотеку fb, то это будет тоже самое , что функция с void?

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 40
Откуда : Россия, Санкт-Петербург

http://eric50.narod.ru

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Re: передача аргументов в процедуры и функции

Сообщение  tux Вс Авг 24, 2008 9:34 am

угу, можно для примера посмотреть как переносят Сишные прототипы функций на FB
tux
tux

Сообщения : 365
Дата регистрации : 2008-04-06
Возраст : 36
Откуда : Сибирь

http://tux.nsk.ru/

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Ассемблер и языки высокого уровня: передача параметров

Сообщение  Замабувараев Сб Июн 06, 2009 12:31 pm

Большинство языков высокого уровня передают параметры вызываемой процедуре в стеке и ожидают возвращения параметров в регистре AX (EAX). иногда используется DX:AX (EDX:EAX), если результат не умещается в одном регистре и ST(0), если результат - число с плавающей запятой.

Конвенция Pascal

Самый очевидный способ вызова процедуры или функции языка высокого уровня, после того как решено, что параметры передаются в стеке и возвращаются в регистре AX/EAX, - это способ, принятый в языке Pascal, - просто поместить параметры в стек в естественном порядке:

запись
some_proc(a, b, c, d, e)

превращается в:

push a
push b
push c
push d
push e

Это означает, что процедура some_proc, во-первых, должна очистить стэк по окончании работы (например, завершившиськомандой ret 10) и, во-вторых, параметры, переданные ей, находятся в стэке в обратном порядке:

some_proc proc
push bp
mov bp, sp ; создать стековый кадр
a equ [bp+12] ; определения для простогодоступа к параметрам
b equ [bp+10]
c equ [bp+8]
d equ [bp+6]
e equ [bp+4]
[текст процедуры, использующей параметры a, b, c, d, e]
pop bp
ret 10
some_proc endp

Главный недостаток этого подхода заключается в сложности создания функции с изменяемым числом параметров. Чтобы определить число параметров, процедура должна сначала прочитать первый параметр, но она не знает его расположения в стэке. Эту проблему решает подход, используемый в C, где параметры передаются в обратном порядке.

Конвенция C

Данный способ передачи параметровиспользуется в первую очередь в языках C и C++. Параметры помещаются в стек в обратном порядке, а удаление из стека (в противоположность Pascal-конвенции) выполняет вызывающая процедура:

запись
some_proc(a, b, c, d, e)

превращается в:

push e
push d
push c
push b
push a
call some_proc
add sp, 10 ; освободить стек

Вызванная процедура может инициализироваться следующим образом:

some_proc proc
push bp
mov bp, sp ; создать стековый кадр
a equ [bp+4] ; определения для простого доступа к параметрам
b equ [bp+6]
c equ [bp+8]
d equ [bp+10]
e equ [bp+12]
[текст процедуры, использующей параметры a, b, c, d, e]
pop bp
ret
some_proc endp

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

push param1
push param2
call proc1
call proc2
add sp, 4

эквивалентно

proc1(param1, param2);
proc2(param1, param2);

вот почему компиляторы с языка C создают более компактный и быстрый код нежели компиляторы с других языков.

Смешанные конвенции

Существует также конвенция STDCALL, отличающаяся и от C, и от PASCAL-конвенций, которая применяется для всех системных функций Win32 API. Здесь параметры помещаются в стект в обратном порядке, как в C, но процедуры должны очищать стек сами, как в PASCAL.

Искажение имён

Компиляторы Microsoft C (а также многие компиляторы UNIX), изменяют названия процедур, чтобы отразить используемый способ передачи параметров. Так, к названиям всех процедур, применяющих C-конвенцию, добавляется символ подчёркивания. То есть, если в C-программе записано

some_proc();

то реально компилятор пишет

call _some_proc

и это означает: если процедура написана на ассемблере, она должна называться именно _some_proc.
Названия процедур, использующих STDCALL, искажаются ещё более сложным образом: слева к названию процедуры добавляется символ подчёркивания, а сзади — сивол @ и размер области стека в байтах, которую занимают параметры (то есть число, стоящее после команды ret в конце процедуры)

some_proc(a:word);

превращается в

push a
call _some_proc@4
Замабувараев
Замабувараев

Сообщения : 99
Дата регистрации : 2008-08-20
Возраст : 40
Откуда : Красноярск

http://www.freebasic.su

Вернуться к началу Перейти вниз

передача аргументов в процедуры и функции Empty Re: передача аргументов в процедуры и функции

Сообщение  Eric-S Пн Июн 08, 2009 7:58 am

Очень знакомый текст. Где-то и когда-то я его уже читал

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 40
Откуда : Россия, Санкт-Петербург

http://eric50.narod.ru

Вернуться к началу Перейти вниз

Вернуться к началу

- Похожие темы

 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения