in reply to Re^6: Perl XS binding to a struct with an array of chars*
in thread Perl XS binding to a struct with an array of chars*
Is it possible to handle that ?struct _Edje_Message_String_Set { int count; char * str[]; };
Yes, it sure is!
I actually decided that this is the best way to implement the idea of the array of pointer within the struct itself. My reasoning is that the [] gives a big clue that there is no storage in the struct at all for the array of pointers to strings.
In my implementation below, I allocated one more slot for a NULL pointer. That is so that more traditional C pointer iteration style can be used as an alternative to using some counter based upon the "count".
Also not that the Perl print statements come before the C print statements! That of course has to be due some buffering weirdness, but I didn't figure out how to defeat that behaviour. Also for some reason, the API function, av_count() wasn't available on my version so a simple workaround calculation was used.
#MessageStorageInsideStruct 11/25/2022 # #https://www.perlmonks.org/?node_id=11148268 # # # use strict; use warnings; use Inline C => Config => BUILD_NOISY => 1, CLEAN_AFTER_BUILD => 1, USING => 'ParseRegExp', ; use Inline "C"; struct_size(); my @in = ("hello foo", "hello bar","hello world", "goodbye", '1', '2', + '3'); foo(\@in); print "back inside Perl program!!!!\n"; print "printout is not in time order you expected!\n\n"; =EXAMPLE RUN back inside Perl program!!!! printout is not in time order you expected! Size of _Edje_Message_String_Set structure: 8 bytes Address of the Message Struct: 000000000308FAB8 Address of the Pointer Array: 000000000308FAC0 setting element 0 string: hello foo's pointer is at Address 000000000308FAC0 setting element 1 string: hello bar's pointer is at Address 000000000308FAC8 setting element 2 string: hello world's pointer is at Address 000000000308FAD0 setting element 3 string: goodbye's pointer is at Address 000000000308FAD8 setting element 4 string: 1's pointer is at Address 000000000308FAE0 setting element 5 string: 2's pointer is at Address 000000000308FAE8 setting element 6 string: 3's pointer is at Address 000000000308FAF0 Dumping an EdjeMessageStringSet Count = 7 1) hello foo 2) hello bar 3) hello world 4) goodbye 5) 1 6) 2 7) 3 Destroying an EdjeMessageStringSet =cut __END__ __C__ /*********** Start of C Code ********/ struct _Edje_Message_String_Set { int count; //On 64 bit machine, this is 8 bytes char *str[]; //str has no "size" and is not counted in sizeof(_Edj +e_Message_String_Set) }; typedef struct _Edje_Message_String_Set EdjeMessageStringSet; void struct_size(void) { printf("Size of _Edje_Message_String_Set structure: %d bytes\n", sizeof(EdjeMessageStringSet) ); } /************/ EdjeMessageStringSet * _new(AV* val_arr) { int count = av_len(val_arr) + 1; // newer av_count() not avail thi +s version // sizeof(Edje_Message_String_Set) only has the integer,count of 8 b +ytes // space for the array of pointers must be allocated by safemalloc // remember to add one more slot for a NULL pointer EdjeMessageStringSet* message = (EdjeMessageStringSet*) safemalloc ( sizeof(EdjeMessageStringSet) + ( +count+1)*sizeof(char*) ); printf ("Address of the Message Struct: %p\n",message); + if(message == NULL) croak("Failed to allocate memory for message in _new function") +; message->count = count; char** p = &(message->str[0]); printf ("Address of the Pointer Array: %p\n", p); int i; for(i= 0; i < message->count; i++) { printf ("setting element %d\n",i); SV** elem = av_fetch(val_arr, i, 0); if (elem==NULL) croak ("bad SV elem value in _new function"); char* string = SvPVutf8_nolen(*elem); printf ("string: %s's pointer is at Address %p\n",string,p); *p++ = savepv(string); } *p = NULL; //Can use either count or NULL pointer as a loop variab +le return message; } /******************/ void _iterate (EdjeMessageStringSet* m) { printf ("Dumping an EdjeMessageStringSet\n"); printf ("Count = %d\n",m->count); int i = 1; char** p = &(m->str[0]); while (*p) {printf ("%d) %s\n",i++,*p++);} } void DESTROY(EdjeMessageStringSet* m) { printf ("Destroying an EdjeMessageStringSet\n"); char** p = &(m->str[0]); while(*p){Safefree(*p++);} //zap eaxh cloned string Safefree(m); //zap main structure } /************/ void foo(AV * arref) { EdjeMessageStringSet* m = _new(arref); _iterate(m); DESTROY(m); }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^8: Perl XS binding to a struct with an array of chars*
by syphilis (Archbishop) on Nov 27, 2022 at 05:23 UTC | |
by Marshall (Canon) on Nov 28, 2022 at 07:31 UTC |