Passing a char[] inside a struct to an FFI call

C. David Shaffer cdshaffer at acm.org
Fri Dec 10 21:51:48 UTC 2004


Hi folks,

I'm stumped on an FFI issue.  I want to allocate and send a:

typedef struct {
  int someNumber;
  char someString[255];
} MyStruct;

into:

int printIt(MyStruct* s, int size);

So I declare an ExternalStructure subclass and specify fields on the 
class side as:

fields
    "self defineFields"
    ^#((someNumber 'long') (someString 'ExternalData' 255))

and

apiPrintIt: me size: size
    <cdecl: long 'printIt' (SCExampleStruct* long) module: 'ffiexample'>
    ^self externalCallFailed

but the generated mutator for someString doesn't copy all 255 bytes of 
my string.  That is, it looks like:

someString: anObject
    "This method was automatically generated"
    handle structAt: 5 put: anObject getHandle length: 4.

My printIt method shows the first 4 bytes of the string but, as 
expected, doesn't get the rest right.  I overrode class side byteSize to 
return 259 (255+4) but that didn't help.  I hate to change this method 
since it was automatically generated and I don't understand the 
concequences of such a change.  How should I really go about this?

I have attached my code (for curious, helpful or insanely bored).  Some 
hints would be helpful.  I've read many of the e-mails on this list 
about FFI but I'm not making progress quickly enough.  Here's my workspace:

s _ SCExampleStruct new.
s someNumber: 10.
s someString: ('hhhhhhhhellllllo world' asExternalCString: 255).
s printMe

Lost and confused,

David

-- 
C. David Shaffer
http://www.cs.westminster.edu/~shaffer
http://www.shaffer-consulting.com

-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 10 December 2004 at 4:49:04 pm'!
ExternalStructure subclass: #SCExampleStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PalmPilot'!

!SCExampleStruct methodsFor: 'accessing' stamp: 'cds 12/10/2004 16:37'!
someNumber
	"This method was automatically generated"
	^handle signedLongAt: 1! !

!SCExampleStruct methodsFor: 'accessing' stamp: 'cds 12/10/2004 16:37'!
someNumber: anObject
	"This method was automatically generated"
	handle signedLongAt: 1 put: anObject! !

!SCExampleStruct methodsFor: 'accessing' stamp: 'cds 12/10/2004 16:37'!
someString
	"This method was automatically generated"
	^ExternalData fromHandle: (handle structAt: 5 length: 4)! !

!SCExampleStruct methodsFor: 'accessing' stamp: 'cds 12/10/2004 16:37'!
someString: anObject
	"This method was automatically generated"
	handle structAt: 5 put: anObject getHandle length: 4.! !


!SCExampleStruct methodsFor: 'apicalls' stamp: 'cds 12/10/2004 12:27'!
apiPrintIt: me size: size
	<cdecl: long 'printIt' (SCExampleStruct* long) module: 'ffiexample'>
	^self externalCallFailed ! !


!SCExampleStruct methodsFor: 'api' stamp: 'cds 12/10/2004 12:28'!
printMe
	self apiPrintIt: self size: 255+4.! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

SCExampleStruct class
	instanceVariableNames: ''!

!SCExampleStruct class methodsFor: 'fields' stamp: 'cds 12/10/2004 16:37'!
byteSize
	^255+4! !

!SCExampleStruct class methodsFor: 'fields' stamp: 'cds 12/10/2004 16:37'!
fields
	"self defineFields"
	^#((someNumber 'long') (someString 'ExternalData' 255))! !


SCExampleStruct compileFields!
-------------- next part --------------
#include "ffiexample.h"

int printIt(MyStruct* s, int size) {
  int i;
  printf("%lx\n", s);
  printf("%d\n", size);
  printf("%d\n", s->someNumber);
  printf("%lx\n", s->someString);
  for(i=0; i < 255; i++) {
    printf("%hhx:", s->someString[i]);
  }
  printf("\n");
}

-------------- next part --------------
typedef struct {
  int someNumber;
  char someString[255];
} MyStruct;
-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 10 December 2004 at 4:51:12 pm'!

!String methodsFor: '*PalmPilot' stamp: 'cds 12/10/2004 16:24'!
asExternalCString: length
	| add |
	add := ExternalAddress allocate: length.
	self halt.
	1 to: self size do: [:i |
		add byteAt: i  put: (self at: i) asciiValue].
	add byteAt: self size + 1 put: 0.
	^ExternalData fromHandle: add type: ExternalType char! !


More information about the Squeak-dev mailing list