Forum > FPC development
Imported C Structure is not mapped correctly
domibay_hugo:
I'm developing an Application that interacts with an External Shared Library over a C Language Structure:
--- Code: C [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---#define MAX_RESULT 128 typedef struct FooResult { uint32_t iversion; int8_t iresultcount; int8_t ierrorcode; int64_t arrresult[MAX_RESULT];} FooResult;
So I created this Pascal Structure:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---const MAX_RESULT = 128; type PResultArray = ^TResultArray; TResultArray = array[0..(MAX_RESULT - 1)] of Int64; PFooResult = ^TFooResult; TFooResult = packed record iversion: cuint32; iresultcount: cint8; ierrorcode: cint8; arrresult: TResultArray; end;
The issue that I'm observing is that the Array TFooResult.arrresult cannot be accessed correctly.
But when reading the Array TResultArray FreePascal shows the values correctly.
The Library Code is:
--- Code: C [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---#include <stdint.h>#include <stdlib.h>#include <stdio.h> #define MAX_RESULT 128 typedef struct FooResult { uint32_t iversion; int8_t iresultcount; int8_t ierrorcode; int64_t arrresult[MAX_RESULT];} FooResult; /* fooutils.h */ extern FooResult* foo_get_result();extern void foo_build_result(FooResult*);extern const int64_t* foo_get_result_array(const FooResult*);extern void foo_result_debug(const FooResult*);extern void foo_result_free(FooResult*); FooResult* foo_get_result(){ FooResult* pfooresult = (FooResult*)malloc(sizeof(FooResult)); int irs; pfooresult->iversion = 0; pfooresult->iresultcount = -1; pfooresult->ierrorcode = 0; for(irs = 0; irs < MAX_RESULT; irs++) { pfooresult->arrresult[irs] = -1; } return pfooresult;} void foo_build_result(FooResult* pfooresult){ if(pfooresult != NULL) { pfooresult->iversion += 1; pfooresult->ierrorcode = 0; if(pfooresult->iresultcount <= 127) { if(pfooresult->iresultcount != -1) { pfooresult->arrresult[pfooresult->iresultcount] = pfooresult->iversion; pfooresult->iresultcount += 1; } else { pfooresult->arrresult[0] = pfooresult->iversion; pfooresult->iresultcount = 1; } //if frs.iresultcount != -1 } else { pfooresult->ierrorcode = 4; } //if(pfooresult->iresultcount <= 127) } //if(pfooresult != Null)} const int64_t* foo_get_result_array(const FooResult* pfooresult){ if(pfooresult != NULL) { return pfooresult->arrresult; } else { return NULL; }} void foo_result_debug(const FooResult* pfooresult){ if(pfooresult != NULL) { int irs; printf("FooResult* Debug: '*FooResult { iversion: %d, iresultcount: %d, ierrorcode: %d" , pfooresult->iversion, pfooresult->iresultcount, pfooresult->ierrorcode); printf(", arrresult: ["); for(irs = 0; irs < MAX_RESULT; irs++) { if(irs > 0) { printf(", "); } printf("%d", (int)pfooresult->arrresult[irs]); } printf("] }'\n"); } else //FooResult is not set { printf("FooResult Debug: 'NULL'\n"); } //if(pfooresult != Null) } void foo_result_free(FooResult* pfooresult){ if(pfooresult != NULL) { free(pfooresult); } }
the C Language Host Application is this:
--- Code: C [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---#include <stdint.h>#include <stdio.h> #define MAX_RESULT 128 typedef struct FooResult { uint32_t iversion; int8_t iresultcount; int8_t ierrorcode; int64_t arrresult[MAX_RESULT];} FooResult; /* foo-utils.h */ extern FooResult* foo_get_result();extern void foo_build_result(const FooResult*);extern const int64_t* foo_get_result_array(const FooResult*);extern void foo_result_debug(const FooResult*);extern void foo_result_free(FooResult*); int main (){ FooResult* pfoors; const uint64_t* parrrs; int irs, igtcnt; printf("FooResult: building ...\n"); pfoors = foo_get_result(); if(pfoors != NULL) { printf("FooResult: built.\n"); printf("FooResult - Debug 0:\n"); foo_result_debug(pfoors); printf("FooResult - Content:\n"); printf("FooResult - Code: [%d]\n", pfoors->ierrorcode); printf("FooResult: Version '%d'\n", pfoors->iversion); printf("FooResult: (Count: '%d / %d'):\n", pfoors->iresultcount, MAX_RESULT); for(irs = 0; irs < pfoors->iresultcount; irs++) { printf("FooResult: Result[%d]: '%d'\n", irs, pfoors->arrresult[irs]); } printf("FooResult: 3 Results filling ...\n"); printf("FooResult: Result 1 filling ...\n"); foo_build_result(pfoors); printf("FooResult - Debug 1:\n"); foo_result_debug(pfoors); printf("FooResult: Result 2 filling ...\n"); foo_build_result(pfoors); printf("FooResult - Debug 2:\n"); foo_result_debug(pfoors); printf("FooResult: Result 3 filling ...\n"); foo_build_result(pfoors); printf("FooResult - Debug 3:\n"); foo_result_debug(pfoors); printf("FooResult: 3 Results filled.\n"); printf("FooResult - Code: [%d]\n", pfoors->ierrorcode); printf("FooResult: Version '%d'\n", pfoors->iversion); printf("FooResult: (Count: '%d / %d'):\n", pfoors->iresultcount, MAX_RESULT); for(irs = 0; irs < pfoors->iresultcount; irs++) { printf("FooResult: Result[%d]: '%d'\n", irs, pfoors->arrresult[irs]); } igtcnt = pfoors->iresultcount; printf("FooResult: Array getting ...\n"); parrrs = foo_get_result_array(pfoors); if(parrrs != NULL) { for(irs = 0; irs < igtcnt; irs++) { printf("FooResult: Array[%d]: '%d'\n", irs, *(parrrs + irs)); } } else //if(parrrs != NULL) printf("FooResult: Array get failed!\n"); } else //if(pfoors != NULL) printf("FooResult: Build failed!\n"); printf("FooResult: deleting ...\n"); foo_result_free(pfoors); printf("FooResult: deleted.\n"); printf("FooResult: App done.\n"); return 0;}
The C Language Host Application can interact with the Library perfectly and reading the field without any issue:
$ ./foo_result
FooResult: building ...
FooResult: built.
FooResult - Debug 0:
FooResult* Debug: '*FooResult { iversion: 0, iresultcount: -1, ierrorcode: 0, arrresult: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult - Content:
FooResult - Code: [ 0 ]
FooResult: Version '0'
FooResult: (Count: '-1 / 128'):
FooResult: 3 Results filling ...
FooResult: Result 1 filling ...
FooResult - Debug 1:
FooResult* Debug: '*FooResult { iversion: 1, iresultcount: 1, ierrorcode: 0, arrresult: [1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: Result 2 filling ...
FooResult - Debug 2:
FooResult* Debug: '*FooResult { iversion: 2, iresultcount: 2, ierrorcode: 0, arrresult: [1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: Result 3 filling ...
FooResult - Debug 3:
FooResult* Debug: '*FooResult { iversion: 3, iresultcount: 3, ierrorcode: 0, arrresult: [1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: 3 Results filled.
FooResult - Code: [ 0 ]
FooResult: Version '3'
FooResult: (Count: '3 / 128'):
FooResult: Result[0]: '1'
FooResult: Result[1]: '2'
FooResult: Result[2]: '3'
FooResult: Array getting ...
FooResult: Array[0]: '1'
FooResult: Array[1]: '2'
FooResult: Array[2]: '3'
FooResult: deleting ...
FooResult: deleted.
FooResult: App done.
Now the corresponding FreePascal Host Application reads only Rubbish.
Which seems to me to be an Issue of Memory Outlay.
The FreePascal Application is this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program demofooresult; uses SysUtils, ctypes; const External_library='libfoo_utils.so'; {Setup as you need} {$IFDEF FPC}{$PACKRECORDS C}{$ENDIF} const MAX_RESULT = 128; type PFooStruct = Pointer; PResultArray = ^TResultArray; TResultArray = array[0..(MAX_RESULT - 1)] of Int64; PFooResult = ^TFooResult; TFooResult = packed record iversion: cuint32; iresultcount: cint8; ierrorcode: cint8; arrresult: TResultArray; end; function foo_get_result(): PFooResult; cdecl; external External_library name 'foo_get_result';procedure foo_build_result(pfoo: PFooResult); cdecl; external External_library name 'foo_build_result';function foo_get_result_array(pfoo: PFooResult): PResultArray; cdecl; external External_library name 'foo_get_result_array';procedure foo_result_debug(pfoo: PFooResult); cdecl; external External_library name 'foo_result_debug';procedure foo_result_free(pfoo: PFooResult); cdecl; external External_library name 'foo_result_free'; var pfoors: PFooResult; parrrs: PResultArray; irs, igtcnt: Integer;begin WriteLn('FooResult: building ...'); pfoors := foo_get_result; if pfoors <> Nil then begin WriteLn('FooResult: built.'); WriteLn('FooResult - Debug 0:'); foo_result_debug(pfoors); WriteLn('FooResult - Content:'); WriteLn('FooResult - Code: [', pfoors^.ierrorcode, ']'); WriteLn('FooResult: Version '#39, pfoors^.iversion, #39); WriteLn('FooResult: (Count: '#39, pfoors^.iresultcount, ' / ', MAX_RESULT, #39'):'); for irs := 0 to pfoors^.iresultcount - 1 do WriteLn('FooResult: Result[', irs, ']: '#39, pfoors^.arrresult[irs], #39'):'); WriteLn('FooResult: 3 Results filling ...'); WriteLn('FooResult: Result 1 filling ...'); foo_build_result(pfoors); WriteLn('FooResult - Debug 1:'); foo_result_debug(pfoors); WriteLn('FooResult: Result 2 filling ...'); foo_build_result(pfoors); WriteLn('FooResult - Debug 2:'); foo_result_debug(pfoors); WriteLn('FooResult: Result 3 filling ...'); foo_build_result(pfoors); WriteLn('FooResult - Debug 3:'); foo_result_debug(pfoors); WriteLn('FooResult: 3 Results filled.'); WriteLn('FooResult - Code: [', pfoors^.ierrorcode, ']'); WriteLn('FooResult: Version '#39, pfoors^.iversion, #39); WriteLn('FooResult: (Count: '#39, pfoors^.iresultcount, ' / ', MAX_RESULT, #39'):'); for irs := 0 to pfoors^.iresultcount - 1 do WriteLn('FooResult: Result[', irs, ']: '#39, pfoors^.arrresult[irs], #39); igtcnt := pfoors^.iresultcount; WriteLn('FooResult: Array getting ...'); parrrs := foo_get_result_array(pfoors); if parrrs <> Nil then begin for irs := 0 to igtcnt - 1 do WriteLn('FooResult: Array[', irs, ']: '#39, parrrs^[irs], #39); end else //if parrrs <> Nil then WriteLn('FooResult: Array get failed!'); end else //if pfoors <> Nil then WriteLn('FooResult: Build failed!'); WriteLn('FooResult: deleting ...'); foo_result_free(pfoors); WriteLn('FooResult: deleted.'); WriteLn('App: done.');end.
which prints this Output:
$ ./demofooresult
FooResult: building ...
FooResult: built.
FooResult - Debug 0:
FooResult* Debug: '*FooResult { iversion: 0, iresultcount: -1, ierrorcode: 0, arrresult: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult - Content:
FooResult - Code: [ 0 ]
FooResult: Version '0'
FooResult: (Count: '-1 / 128'):
FooResult: 3 Results filling ...
FooResult: Result 1 filling ...
FooResult - Debug 1:
FooResult* Debug: '*FooResult { iversion: 1, iresultcount: 1, ierrorcode: 0, arrresult: [1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: Result 2 filling ...
FooResult - Debug 2:
FooResult* Debug: '*FooResult { iversion: 2, iresultcount: 2, ierrorcode: 0, arrresult: [1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: Result 3 filling ...
FooResult - Debug 3:
FooResult* Debug: '*FooResult { iversion: 3, iresultcount: 3, ierrorcode: 0, arrresult: [1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] }'
FooResult: 3 Results filled.
FooResult - Code: [ 0 ]
FooResult: Version '3'
FooResult: (Count: '3 / 128'):
FooResult: Result[0]: '65536'
FooResult: Result[1]: '131072'
FooResult: Result[2]: '196608'
FooResult: Array getting ...
FooResult: Array[0]: '1'
FooResult: Array[1]: '2'
FooResult: Array[2]: '3'
FooResult: deleting ...
FooResult: deleted.
App: done.
Heap dump by heaptrc unit of /plath/to/demofooresult
6 memory blocks allocated : 719/728
6 memory blocks freed : 719/728
0 unfreed memory blocks : 0
True heap size : 327680
True free heap : 327680
the direct access to TFooResult.arrresult prints only Rubbish although the Array is as Static Array defined:
FooResult - Code: [ 0 ]
FooResult: Version '3'
FooResult: (Count: '3 / 128'):
FooResult: Result[0]: '65536'
FooResult: Result[1]: '131072'
FooResult: Result[2]: '196608'
marcov:
You declare your Pascal structure as packed. You don't declare your C struct as packed.
Solution: declare your C struct as packed by whatever means your C compiler allows.
(or remove the packed and add {$packrecords C} above the record in Pascal, which is the most likely packing default for a C compiler).
domibay_hugo:
Thank you very much for this Tip!
the access to the Array TFooResult.arrresult works now correctly.
Although I had the understanding that the packed record definition is required to match with C Language Library Definitions.
I also found that the unit ctypes includes the .inc file /rtl/linux/ptypes.inc
which again defines the directives:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$I ctypes.inc}{$packrecords c}
PascalDragon:
--- Quote from: domibay_hugo on January 04, 2021, 04:48:11 pm ---Although I had the understanding that the packed record definition is required to match with C Language Library Definitions.
--- End quote ---
No. packed ensures that there is no padding between fields of a record. That is not the case by default in C.
--- Quote from: domibay_hugo on January 04, 2021, 04:48:11 pm ---I also found that the unit ctypes includes the .inc file /rtl/linux/ptypes.inc
which again defines the directives:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$I ctypes.inc}{$packrecords c}
--- End quote ---
That only applies to the records declared inside the ctypes unit (and only if they aren't declared as packed).
marcov:
--- Quote from: domibay_hugo on January 04, 2021, 04:48:11 pm --- Although I had the understanding that the packed record definition is required to match with C Language Library Definitions.
--- End quote ---
I was not aware that the C language standard said something about packing. Usually standards are very restrictive to specify too much about it.
Navigation
[0] Message Index
[#] Next page