Function returning an array

General FreeBASIC programming questions.
AlejandroPadrino
Posts: 22
Joined: Sep 01, 2011 15:54
Location: Madrid-Spain
Contact:

Function returning an array

Postby AlejandroPadrino » Sep 28, 2012 23:49

Hello to all members,

can be possible Free-Basic returns an array from one custom function? Anyone can write sample sourcecode?

Thanks. ;-)
Destructosoft
Posts: 88
Joined: Apr 03, 2011 3:44
Location: Inside the bomb
Contact:

Re: Function returning an array

Postby Destructosoft » Sep 29, 2012 0:41

Code: Select all

type array
  a(1000)as byte
end type

declare function arr as array

dim as array a
randomize
cls

a=arr
sleep:end

function arr as array
dim as array a
dim as integer t
  for t=0 to 1000
    a.a(t)=int(rnd*100)+1
  next
  return a
end function
t3rt3l
Posts: 20
Joined: Jun 19, 2012 9:04
Location: California, US
Contact:

Re: Function returning an array

Postby t3rt3l » Sep 29, 2012 1:32

You could make a sub that takes an array and writes to it.

Code: Select all

sub fill (array() as integer)
    for i as integer = 0 to ubound(array)
        array(i) = i
    next
end sub
Richard
Posts: 2942
Joined: Jan 15, 2007 20:44
Location: Australia

Re: Function returning an array

Postby Richard » Sep 29, 2012 1:43

Be aware that you are only passing the address of the array, BYREF, not the array itself.
AlejandroPadrino
Posts: 22
Joined: Sep 01, 2011 15:54
Location: Madrid-Spain
Contact:

Re: Function returning an array

Postby AlejandroPadrino » Sep 29, 2012 8:27

Thank you for replies. I think Destructosoft's sample is that I need.

Best. :-)
fxm
Posts: 9010
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function returning an array

Postby fxm » Sep 29, 2012 8:53

AlejandroPadrino wrote:Thank you for replies. I think Destructosoft's sample is that I need.

Best. :-)

Remark: this solution (array encapsulated in a type) can process only static arrays.
fxm
Posts: 9010
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function returning an array

Postby fxm » Sep 29, 2012 12:20

- If we use a 'function () As UDT', the object containing the array is entirely passed in the stack, and consequently the available array size is limited by the free stack size.
- If we use a 'function () As UDT Ptr', only the pointer to the object containing the array is passed in the stack, and consequently the available array size is not limited by the free stack size.

(see my previous post: viewtopic.php?p=166413#p166413)
AlejandroPadrino
Posts: 22
Joined: Sep 01, 2011 15:54
Location: Madrid-Spain
Contact:

Re: Function returning an array

Postby AlejandroPadrino » Sep 29, 2012 14:28

Very useful information, Fxm.

Thank you. :-)
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Function returning an array

Postby MichaelW » Sep 29, 2012 17:53

I set out to determine how much longer it took to return an array on the stack, compared to returning a pointer, but examining the assembly code it looks like the array is not actually returned on the stack, but copied to an address that is passed in the call. It will end up on the stack only if the receiving array is allocated from the stack.

Code: Select all

type arraytype
    array(10000)as integer
end type

function ReturnOnStack() as arraytype
    dim as arraytype array
    for i as integer = 0 to 100
        array.array(i) = i
    next
    asm nop
    return array
    asm nop
end function

function ReturnPtr() as arraytype ptr
    dim as arraytype array
    for i as integer = 0 to 100
        array.array(i) = i
    next
    return @array
end function


dim as arraytype r
dim as arraytype ptr p
dim as double t

sleep 5000

t = timer
r = ReturnOnStack()
print using "##.##ms returning on stack";(timer-t) * 1000

for i as integer = 1 to 100
    print r.array(i),
next
print

t = timer
p = ReturnPtr()
print using "##.##ms returning pointer";(timer-t) * 1000

for i as integer = 1 to 100
    print p->array(i),
next
print

sleep
fxm
Posts: 9010
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function returning an array

Postby fxm » Sep 29, 2012 18:51

MichaelW wrote:..., but examining the assembly code it looks like the array is not actually returned on the stack, but copied to an address that is passed in the call. It will end up on the stack only if the receiving array is allocated from the stack.

I do not well understand!

This following example is issued from a post of me (see my previous post):
- The object containing the array seems to be returned in the system stack memory (1 MB), because it crashes if array is too big, while 'UDT0' is 'Static' and 'UDT1' is 'Shared'!

Code: Select all

Type UDT
'  array(1023, 1023) As Byte ' does not work (stack overflow => crash)
  array(511, 511) As Byte
End Type

Function Get_Array () As UDT
  Static UDT0 AS UDT ' not in stack
  For I As Integer = 0 To 9
    For J As Integer = 0 To 9
      UDT0.array(I, J) = I * 10 + J
    Next J
  Next I
  Function = UDT0 ' a copy of UDT0 is put in the stack,
  Erase UDT0.array ' then we can erase array of UDT0
End Function

Dim Shared UDT1 As UDT ' not in stack
UDT1 = Get_Array()
For I As Integer = 0 To 9
  For J As Integer = 0 To 9
    Print Using "###"; UDT1.array(I, J);
  Next J
  Print "..."
Next I
Print "..."
Print "array size:"; Sizeof(UDT); " bytes ="; Sizeof(UDT) / 1024 / 1024; " MB"
Sleep
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Function returning an array

Postby MichaelW » Sep 29, 2012 19:14

Here is a partially commented version of the assembly code:

Code: Select all

   .intel_syntax noprefix

   #test.bas' compilation started at 12:41:59 (FreeBASIC 0.24.0)

.section .text
.balign 16

.globl _RETURNONSTACK@4
_RETURNONSTACK@4:
push ebp
mov ebp, esp
sub esp, 40008                    ; allocate stack space for local array
push ebx
push esi
push edi
.Lt_0004:
lea eax, [ebp-40004]              ; load ebx with address of local array
push eax
mov edi, eax
xor eax, eax
mov ecx, 10001
rep stosd                         ; fill local array with zeros
pop eax
mov dword ptr [ebp-40008], 0
.Lt_000A:
lea eax, [ebp-40004]
mov ebx, dword ptr [ebp-40008]
sal ebx, 2
add eax, ebx
mov ebx, dword ptr [ebp-40008]
mov dword ptr [eax], ebx
.Lt_0008:
inc dword ptr [ebp-40008]
.Lt_0007:
cmp dword ptr [ebp-40008], 100
jle .Lt_000A
.Lt_0009:
nop
lea ebx, [ebp-40004]            ; load ebx with address of local array
mov edi, dword ptr [ebp+8]      ; load edi with passed in address
mov esi, ebx                    ; load esi with address of local array
mov ecx, 10001                  ; set count
rep movsd                       ; copy from local array to receiving array
jmp .Lt_0005
nop
.Lt_0005:
mov eax, dword ptr [ebp+8]      ; set return value to passed in address
pop edi                         ; the above appears to be discarded on return
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
.balign 16

.globl _RETURNPTR@0
_RETURNPTR@0:
push ebp
mov ebp, esp
sub esp, 40012
push ebx
mov dword ptr [ebp-4], 0
.Lt_000B:
lea eax, [ebp-40008]
push eax
push edi
mov edi, eax
xor eax, eax
mov ecx, 10001
rep stosd
pop edi
pop eax
mov dword ptr [ebp-40012], 0
.Lt_0010:
lea eax, [ebp-40008]
mov ebx, dword ptr [ebp-40012]
sal ebx, 2
add eax, ebx
mov ebx, dword ptr [ebp-40012]
mov dword ptr [eax], ebx
.Lt_000E:
inc dword ptr [ebp-40012]
.Lt_000D:
cmp dword ptr [ebp-40012], 100
jle .Lt_0010
.Lt_000F:
lea ebx, [ebp-40008]
mov dword ptr [ebp-4], ebx
.Lt_000C:
mov eax, dword ptr [ebp-4]
pop ebx
mov esp, ebp
pop ebp
ret
.balign 16

.globl _main
_main:
push ebp
mov ebp, esp
and esp, 0xFFFFFFF0
sub esp, 80028                    ; allocate stack space for 2 arrays
push ebx
mov dword ptr [ebp-4], 0
call ___main
push 0
push dword ptr [ebp+12]
push dword ptr [ebp+8]
call _fb_Init@12
.Lt_0002:
lea eax, [ebp-40008]
push eax
push edi
mov edi, eax
xor eax, eax
mov ecx, 10001
rep stosd
pop edi
pop eax
mov dword ptr [ebp-40012], 0
mov dword ptr [ebp-40020], 0
mov dword ptr [ebp-40016], 0
push 5000
call _fb_Sleep@4
call _fb_Timer@0
fstp qword ptr [ebp-40020]
lea eax, [ebp-40008]
lea ebx, [ebp-80024]         
push eax
push edi
mov edi, ebx
xor eax, eax
mov ecx, 10001
rep stosd
pop edi
pop eax
lea ebx, [ebp-80024]              ; load ebx with address of receiving array
push ebx                          ; push address
mov ebx, eax
call _RETURNONSTACK@4             ; call function
lea eax, [ebp-80024]
push edi
push esi
mov edi, ebx
mov esi, eax
mov ecx, 10001
rep movsd
pop esi
pop edi
push 26
push offset _Lt_0012
call _fb_StrAllocTempDescZEx@8
push eax
call _fb_PrintUsingInit@4
push -2147483647
call _fb_Timer@0
fsub qword ptr [ebp-40020]
fmul qword ptr [_Lt_001C]
sub esp,8
fstp qword ptr [esp]
push 0
call _fb_PrintUsingDouble@16
push 0
call _fb_PrintUsingEnd@4
mov dword ptr [ebp-80028], 1
.Lt_0016:
push 2
lea eax, [ebp-40008]
mov ebx, dword ptr [ebp-80028]
sal ebx, 2
add eax, ebx
push dword ptr [eax]
push 0
call _fb_PrintInt@12
.Lt_0014:
inc dword ptr [ebp-80028]
.Lt_0013:
cmp dword ptr [ebp-80028], 100
jle .Lt_0016
.Lt_0015:
push 1
push 0
call _fb_PrintVoid@8
call _fb_Timer@0
fstp qword ptr [ebp-40020]
call _RETURNPTR@0
mov dword ptr [ebp-40012], eax
push 25
push offset _Lt_0017
call _fb_StrAllocTempDescZEx@8
push eax
call _fb_PrintUsingInit@4
push -2147483647
call _fb_Timer@0
fsub qword ptr [ebp-40020]
fmul qword ptr [_Lt_001C]
sub esp,8
fstp qword ptr [esp]
push 0
call _fb_PrintUsingDouble@16
push 0
call _fb_PrintUsingEnd@4
mov dword ptr [ebp-80028], 1
.Lt_001B:
push 2
mov eax, dword ptr [ebp-80028]
sal eax, 2
mov ebx, dword ptr [ebp-40012]
add ebx, eax
push dword ptr [ebx]
push 0
call _fb_PrintInt@12
.Lt_0019:
inc dword ptr [ebp-80028]
.Lt_0018:
cmp dword ptr [ebp-80028], 100
jle .Lt_001B
.Lt_001A:
push 1
push 0
call _fb_PrintVoid@8
push -1
call _fb_Sleep@4
.Lt_0003:
push 0
call _fb_End@4
mov eax, dword ptr [ebp-4]
pop ebx
mov esp, ebp
pop ebp
ret
   #test.bas' compilation took 0.005746540420176416 secs

.section .data
.balign 4
_Lt_0012:   .ascii   "##.##ms returning on stack\0"
.balign 4
_Lt_0017:   .ascii   "##.##ms returning pointer\0"
.balign 8
_Lt_001C:   .double   1000


It looks like the returned array is being copied again after the function returns, and it seems to me that this should not be necessary if the correct address was passed to the function. I'm out of time to investigate, for now.
fxm
Posts: 9010
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function returning an array

Postby fxm » Sep 29, 2012 20:02

I modified my previous program, adding to UDT a 'Let' operator to monitor the assignment:

Code: Select all

Type UDT
'  array(1023, 1023) As Byte ' does not work (stack overflow => crash)
  array(511, 511) As Byte
  Declare Operator Let (Byref rhs As UDT)
End Type
Operator UDT.Let (Byref rhs As UDT)
  Dim stack As Integer
  Print "(@stack:"; @stack; ")   @This:"; @This; "   @rhs:"; @rhs
  For I As Integer = 0 To Ubound(This.array, 1)
    For J As Integer = 0 To Ubound(This.array, 2)
      This.array(I, J) = rhs.array(I, J)
    Next J
  Next I
End Operator

Function Get_Array () As UDT
  Static UDT0 AS UDT ' not in stack
  For I As Integer = 0 To 9
    For J As Integer = 0 To 9
      UDT0.array(I, J) = I * 10 + J
    Next J
  Next I
  Function = UDT0 ' a copy of UDT0 is put in the stack,
  Erase UDT0.array ' then we can erase array of UDT0
End Function

Dim Shared UDT1 As UDT ' not in stack
UDT1 = Get_Array()
For I As Integer = 0 To 9
  For J As Integer = 0 To 9
    Print Using "###"; UDT1.array(I, J);
  Next J
  Print "..."
Next I
Print "..."
Print "array size:"; Sizeof(UDT); " bytes ="; Sizeof(UDT) / 1024 / 1024; " MB"
Sleep

Code: Select all

(@stack:982724)   @This:982868   @rhs:4239368
(@stack:982812)   @This:4501512   @rhs:982868
  0  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 35 36 37 38 39...
 40 41 42 43 44 45 46 47 48 49...
 50 51 52 53 54 55 56 57 58 59...
 60 61 62 63 64 65 66 67 68 69...
 70 71 72 73 74 75 76 77 78 79...
 80 81 82 83 84 85 86 87 88 89...
 90 91 92 93 94 95 96 97 98 99...
...
array size: 262144 bytes = 0.25 MB
- '@This:982868 @rhs:4239368' corresponds to 'Function = UDT0' with This=Function and rhs=UDT0,
- '@This:4501512 @rhs:982868' corresponds to 'UDT1 = Get_Array()' with This=UDT1 and rhs=Get_Array() that is well in the stack.
- Besides, @Function = @Get_Array() in the stack => not double copying apparently in the stack.

Return to “General”

Who is online

Users browsing this forum: albert and 2 guests