Page 1 of 1

Pass Structure To Prototype/Procedure By Value?

Posted: Sat Aug 27, 2016 7:32 pm
by skywalk
I had to create a Prototype to an external dll which passes a structure by value. I wondered why it is not supported? And is the workaround of passing a copy of the structure below correct? I am fuzzy on this...

Code: Select all

PASS STRUCTURES TO FUNCTION:   C     PB
1. By value.                   1     0 - Why?
2. By reference(address).      1     1
3. As Global variable.         1     1

Code: Select all

Structure myStruc
  i.i
  x.d
  y.d
EndStructure
Global mySt.myStruc
mySt\i = 1
mySt\x = 2.1
mySt\y = 3.1

;Prototype UseStrucByVal(p.myStruc, Var2.i)   ;<-- ByVal  = Syntax error.
PrototypeC UseStrucByVal(*p_myStruc, Var2.i)  ;<-- ByCopy = OK.

;Procedure UseStrucByVal(p.myStruc, Var2.i)   ;<-- ByVal  = Syntax error.
ProcedureC UseStrucByVal(*p_myStruc, var2.i)  ;<-- ByCopy = OK.
  Debug "-- UseStrucByVal --"
  Debug PeekI(*p_myStruc + 0)
  Debug PeekD(*p_myStruc + OffsetOf(myStruc\x))
  Debug PeekD(*p_myStruc + OffsetOf(myStruc\y))
  PokeI(*p_myStruc + 0, var2)
EndProcedure
Procedure UseStrucByRef(*p.myStruc, Var2.i)   ;<-- ByRef  = OK.
  Debug "-- UseStrucByRef --"
  Debug *p\i
  Debug *p\x
  Debug *p\y
EndProcedure

Define doProtoByVal.UseStrucByVal = @UseStrucByVal()
Define.i *p = AllocateMemory(SizeOf(myStruc))
CopyStructure(@mySt, *p, myStruc)

UseStrucByVal(*p, 99)
UseStrucByRef(@mySt, 99)
UseStrucByVal(*p, 99)     ;<-- Show edited copy of mySt
ShowCallstack()
doProtoByVal(*p, 999)
FreeMemory(*p)
UseStrucByRef(@mySt, 99)  ;<-- Show unedited mySt

Re: Pass Structure To Prototype/Procedure By Value?

Posted: Sat Aug 27, 2016 10:29 pm
by DontTalkToMe
It's not supported and it's not possible unless the structure is very small (and you still need to be lucky)

http://purebasic.fr/english/viewtopic.php?f=13&t=61916

http://www.purebasic.fr/english/viewtop ... 13&t=47006

Also even different C compilers implements this in different ways, sometimes the structure is passed via the stack, sometimes by registers.

Binary compatibility hence is not guaranteed and unfortunately this is good enough reason to not support it (when calling not PB code, intra-PB of course could be implemented).

Possible solutions if the trick mentioned in the threads above is not feasible: write a C wrapper using a compatible compiler to build a layer which bridge the two conventions, or write specific code probably in asm once you have determined how the structure is passed in the binary implementation you want to call.

Re: Pass Structure To Prototype/Procedure By Value?

Posted: Sat Aug 27, 2016 11:53 pm
by skywalk
Wait, what?
Isn't the point of a compiler to do those necessary steps that are clearly defined for a confined set of datatypes and calling conventions? My understanding is C initially only supported ByRef Struct's, but modern C compilers extended support to ByVal. I see no mention of the perils you outline? Maybe it is later on when you attempt to compile with larger struct's? But I cannot find it in the few C compiler manuals I read.

Re: Pass Structure To Prototype/Procedure By Value?

Posted: Sun Aug 28, 2016 4:28 am
by Lunasole
DontTalkToMe wrote: Possible solutions if the trick mentioned in the threads above is not feasible: write a C wrapper using a compatible compiler to build a layer which bridge the two conventions, or write specific code probably in asm once you have determined how the structure is passed in the binary implementation you want to call.
Yes, the wrappers or modification of original function are the only solution as for me.
Fortunately I recently not often seeing C code which is written so badly and requires byval.

Btw, I just had some idea - what if pass structure as a list of arguments? Can it work somehow (by fact the byval structure in C is not byval as I remember)?

Code: Select all

; for example, here is function which wants structure byval
Procedure A (STRUCTUREBYVAL)

; but let declare it this way when importing it
Procedure A (STRUCTUREFIELD1, STRUCTUREFIELD2, ..., STRUCTUREFIELD20)

Re: Pass Structure To Prototype/Procedure By Value?

Posted: Sun Aug 28, 2016 11:20 am
by DontTalkToMe
http://stackoverflow.com/questions/1617 ... -passing-a
http://stackoverflow.com/questions/2677 ... ction-in-c
http://www.agner.org/optimize/calling_conventions.pdf, page 20

the pdf above is for C++ compilers, but the methods outlined there for structures are used by recent C compilers too.

anyway the problem is the implementation is compiler specific, and it's even more fragmented when you put cross-platform compilers in the mix:
some generate code to copy the structure on the stack, some to allocate space in the heap and memcopy it (slower but it saves stack space), some use registers for certain sizes but maybe only on x64 and not x86, etc.

Re: Pass Structure To Prototype/Procedure By Value?

Posted: Sun Aug 28, 2016 6:09 pm
by skywalk
Yeah, reading more on this last night...My take away is there may be a possibile speed improvement when passing a structure by value because it saves the function from having to dereference constantly. And no threat of altering the original structure.
But, the overall opinion is it has limited application and is not advised if the structure is large and contains nested data structures/pointers. Or if you target multiple processors. And many more "against's" than "for's".

I came upon this requirement in a rare case and did not realize how deep a rabbit hole it becomes. :?