internally C-function does a malloc call: myStructInstancePtr->ptr = (int*)malloc(itemAmount * sizeof(int));
The content of "c-out-arr-grp" does not arrive correctly, event hough the item count is aligned between C and COBOL routines. Any tips would be great.
P.S. I have already went through "GnuCOBOL interfacing COBOL and C" pdf.
P.P.S. I have also tried struct __attribute__ ((__packed__)) mystruct
but it didn't help.
[resent as this post was strangely removed]
@univac Can you please give a bit more information on the system (GCC
based, GNU/Linux?) and GnuCOBOL version, as well as ass the compile
command(s) used?
Have you tried CALL STATIC "cmalloc" as well?
👍
1
Last edit: Simon Sobisch 2024-09-24
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Compiler version (used under Microsoft Windows [Version 10.0.17763.6189]) :
Setting environment for GnuCOBOL 2.0 RC-2 with MinGW binaries
(GCC 5.3.0, PDcurses 3.4, GMP 6.1.1, BDB 6.2.23.NC)
cobc (GnuCOBOL) 2.0.0
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch, Edward Hart
Built Nov 13 2016 01:30:50
Packaged Nov 06 2016 22:36:19 UTC
C version "5.3.0"
It seems that when I'm trying to dereference C-structure in my COBOL code, I get 8 bytes total, while unsigned short takes 4 bytes and pointer to int array is also 4 bytes.
Now, I'm able to see the right value of the primitive unsigned short, but dereferencing structure member int * ptr always fails for me. Either I'm getting "memory not allocated" when trying to access the int array, after set address of cobol-arr to c-int-ptr, or im getting "garbage" from the memory, when dereferencing it like this: set address of cobol-arr to address of c-int-ptr (i know it's the wrong way to dereference).
Last edit: Wild Eest 2024-09-24
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
I think, it would be better to give back the result value not in "returning". The RETURNING clause allows you to specify a numeric data item into which the subroutine should return a numeric value. It is same as with the RETURN-CODE special register. The RETURN-CODE defined as BINARY-LONG SIGNED. These values in RETURN-CODE are by convention used to signify success (usually with a value of 0) or failure (usually with a non-zero value) of the process the program was attempting to perform.
You can write a C wrapper function for the cmalloc, and give back the pointer in the argument, not in Returning.
László
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
this was a bit of a tricky one to find, the issue is NOT big_endian / little_endian but rather the structure padding in C
What is Structure Padding in C?
Structure padding in C is the process that is handled by the CPU architecture. Structure Padding adds a certain number of empty bytes within a structure so that the data members are naturally aligned in memory. The alignment requirements are determined by the processor architecture rather than the language itself. Naturally, the alignment requirements change as per the data bus size or other architectural considerations of a certain CPU architecture.
#include<windows.h>struct__attribute__((packed))mystruct3{charbeginstr[13];shortitemsize;intintarr[5];charendstr[13];};voidcstructdemo(intitemamount,structmystruct3*mystructptr){mystructptr->itemsize=sizeof(int);//----------------------intiarr[]={101,202,-303,404,505};memcpy(mystructptr->intarr,iarr,sizeof(mystructptr->intarr));//----------------------charcarrbeginstr[]="*** begin ***";strncpy(mystructptr->beginstr,carrbeginstr,13);//----------------------charcarrendstr[]="**** end ****";strncpy(mystructptr->endstr,carrendstr,13);return;}
I had to read the programmers guide to understand this bastardization of COBOL.
I was wrong !
I think that binary-int is perhaps big endian
Try PIC S9(08) comp-5 for binary-int
For "short" PIC S9(04) comp-5
So these are GNU extensions ?
I would presume they are little endian on X86 hardware.
COBOL C
BINARY-CHAR UNSIGNED unsigned char
BINARY-CHAR [ SIGNED ] signed char
BINARY-SHORT UNSIGNED unsigned short
BINARY-SHORT [ SIGNED ] short
BINARY-LONG UNSIGNED unsigned long
BINARY-LONG [ SIGNED ] long
BINARY-INT int
BINARY-C-LONG [ SIGNED ] long
BINARY-DOUBLE UNSIGNED unsigned long long
BINARY-DOUBLE [ SIGNED ] long long
BINARY-LONG-LONG long lon
Last edit: Ralph Linkletter 2024-10-07
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you everyone!
The only thing that helped me was SYNC by @laszloerdos
(attribute packed and changing BINARY types to COBOL equivalents - didn't).
I wish it was easier to figure out, but I'm also happy that it worked eventually :)
Code snippet below:
/*-----------------------------------------------------*------------------------------------^---------------------------*identificationdivision.program-id.aaaMAIN.datadivision.*------------------------------------^---------------------------*working-storagesection.01item-amntbinary-intvalue5.01ipic9(3)value0.01c-out-struct-grp.03c-begin-strpicx(13)valuespaces.*03c-item-size-in-bytesbinary-shortvalue0.03c-item-size-in-bytesPICS9(04)comp-5SYNCvalue0.03c-out-arr-grp.*05arr-itembinary-intoccurs5.05arr-itemPICS9(08)comp-5occurs5.03c-end-strpicx(13)valuespaces.*------------------------------------^---------------------------*proceduredivision.call"cstructdemo"usingbyvalueitem-amntbyreferencec-out-struct-grp.display"01: "c-begin-str.display"02: "c-item-size-in-bytes.display"03: "c-out-arr-grp.display"04: "c-end-str.performvaryingifrom1by1untili>5display" 05: "arr-item(i)end-perform.display"06: size of c-out-struct-grp: "functionlength(c-out-struct-grp).goback.endprogramaaaMAIN.*------------------------------------^---------------------------*---------------------------------------------------*///------------------aaaSUB.c---------------------------#include <windows.h>#include <stdio.h>struct__attribute__((packed))mystruct3{charbeginStr[13];shortitemSize;intintArr[5];charendStr[13];};voidcstructdemo(intitemAmount,structmystruct3*myStructPtr){myStructPtr->itemSize=sizeof(int);//----------------------intiArr[]={101,202,-303,404,505};memcpy(myStructPtr->intArr,iArr,sizeof(myStructPtr->intArr));//----------------------charcArrBeginStr[]="*** begin ***";strncpy(myStructPtr->beginStr,cArrBeginStr,13);//----------------------charcArrEndStr[]="**** end ****";strncpy(myStructPtr->endStr,cArrEndStr,13);//----------------------printf("07: size of mystruct3: %d\n",sizeof(structmystruct3));//----------------------return;}/*-----------------OUTPUT----------------------07:sizeofmystruct3:4901:***begin***02:+000403:e╩╤■ö∙04:****end****05:+0000010105:+0000020205:-0000030305:+0000040405:+0000050506:sizeofc-out-struct-grp:000000049-------------------------------------------------*/
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unfortunally for me - it wasn't enough. I have now went back to attribute((packed)) in C and BINARY-INT, BINARY-SHORT without SYNC in GnuCOBOL, and I still have the issue this way, including (due to?) difference in structure size (COBOL 48 bytes vs C 49 bytes) 🤷♂️
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I wonder if your COBOL structure passed a redefines of the binary fields as character.
That is:
77 item-amnt binary-int.
77 item-amnt-char redefines item-amnt pic x(04).
move 5 to item-amnt
COBOL would be indifferent to the type cast
Would "C" insist on padding a char field?
Is it that "C" would pad any data field of an odd length - even char ?
The value contained in a four byte field is universal - irrespective of the description.
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have finally managed to understand how 48 bytes structure transforms into 52 bytes (this is well aligned with x86_64 ABI documentation, specifically - c structure padding):
struct mystruct3 { char beginStr[13]; short itemSize; int intArr[5]; char endStr[13];} ;----------------------------------------------------sum = 0----------------------------------------------------current: type char, align 1, amount 13, size 13sum = sum + current = 13 (aligned)----------------------------------------------------current: type short, align 2, amount 1, size 2 sum = sum + current = 15 (NOT aligned), 15->16 (aligned)----------------------------------------------------current: type integer, align 4, amount 5, size 20sum = sum + current = 36 (aligned)----------------------------------------------------current: type char, align 1, amount 13, size 13sum = sum + current = 49 (aligned)---------------------------------------------------total: type mystruct3, align 4, amount 1, size 49 (NOT aligned)sum = 49->52 (aligned)---------------------------------------------------
So, what I've learned is:
1. COBOL has nothing to do with this behavior
2. the arch of the machine is important (Captain-Obvious moment)
3. order of members inside c structure is important
4. from COBOL perspective the "issue" can be easily solved by FILLERs (tested), but it will make the source code non-portable
5. right way to share structure between COBOL and C is: __attribute__((packed)) + SYNC
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I saw what you did with the code and I used AI to help understand it. Thank you for the cool tutorial on how to pack so that the code is portable across architectures.
Hello, Chuck.
You're only 50% right according to my testing :))
It seems that older version of GnuCOBOL doesn't handle packed C-structure correctly.
This problematic version is distributed with OpenCobolIDE 4.7.6 - not able to sync without SYNC keyword:
cobc (GnuCOBOL) 2.0.0
Copyright (C) 2016 Free Software Foundation, Inc.
Built Nov 13 2016 01:30:50
C version "5.3.0"
On the other hand this version (below) does not require SYNC keyword (like you've said earlier - only needs 'attribute packed' in the C-code):
GnuCOBOL 3.2.0
Built Jul 28 2023 22:59:53
C version (MinGW) "9.2.0"
Thank you for your feedback.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello, Chuck.
You're only 50% right according to my testing :))
It seems that older version of GnuCOBOL doesn't handle packed C-structure correctly.
This problematic version is distributed with OpenCobolIDE 4.7.6 - not able to sync without SYNC keyword:
cobc (GnuCOBOL) 2.0.0
Copyright (C) 2016 Free Software Foundation, Inc.
Built Nov 13 2016 01:30:50
C version "5.3.0"
On the other hand this version (below) does not require SYNC keyword (like you've said earlier - only needs 'attribute packed' in the C-code):
GnuCOBOL 3.2.0
Built Jul 28 2023 22:59:53
C version (MinGW) "9.2.0"
Wild Eest wrote on 2024/09/23:
[resent as this post was strangely removed]
@univac Can you please give a bit more information on the system (GCC
based, GNU/Linux?) and GnuCOBOL version, as well as ass the compile
command(s) used?
Have you tried
CALL STATIC "cmalloc"
as well?Last edit: Simon Sobisch 2024-09-24
Hey, Simon. Thanks for restoring the posts!
Compiler version (used under Microsoft Windows [Version 10.0.17763.6189]) :
Compile commands:
1.
set_env.cmd
2.
cobc -x -o hello hello.cob msgbox.c
No, I haven't tried CALL STATIC yet.
It seems that when I'm trying to dereference C-structure in my COBOL code, I get 8 bytes total, while unsigned short takes 4 bytes and pointer to int array is also 4 bytes.
Now, I'm able to see the right value of the primitive unsigned short, but dereferencing structure member int * ptr always fails for me. Either I'm getting "memory not allocated" when trying to access the int array, after set address of cobol-arr to c-int-ptr, or im getting "garbage" from the memory, when dereferencing it like this: set address of cobol-arr to address of c-int-ptr (i know it's the wrong way to dereference).
Last edit: Wild Eest 2024-09-24
"[resent as this post was strangely removed]"
sorry mixed it up with some spam... I will be more careful
Hi,
I think, it would be better to give back the result value not in "returning". The RETURNING clause allows you to specify a numeric data item into which the subroutine should return a numeric value. It is same as with the RETURN-CODE special register. The RETURN-CODE defined as BINARY-LONG SIGNED. These values in RETURN-CODE are by convention used to signify success (usually with a value of 0) or failure (usually with a non-zero value) of the process the program was attempting to perform.
You can write a C wrapper function for the cmalloc, and give back the pointer in the argument, not in Returning.
László
Hi, sorry for late reply - I was ill.
I've tried returning structure via the input ('by reference' input) and I still get something weird at the end, example:
Wild Eest,
this was a bit of a tricky one to find, the issue is NOT big_endian / little_endian but rather the structure padding in C
What is Structure Padding in C?
Structure padding in C is the process that is handled by the CPU architecture. Structure Padding adds a certain number of empty bytes within a structure so that the data members are naturally aligned in memory. The alignment requirements are determined by the processor architecture rather than the language itself. Naturally, the alignment requirements change as per the data bus size or other architectural considerations of a certain CPU architecture.
see this link...
https://www.tutorialspoint.com/cprogramming/c_structure_padding_and_packing.htm
====> Note the attribute below
+01024 would indicate a big / little endian problem.
use pic 9 (xx) comp-5 instead of "binary"
I had to read the programmers guide to understand this bastardization of COBOL.
I was wrong !
I think that binary-int is perhaps big endian
Try PIC S9(08) comp-5 for binary-int
For "short" PIC S9(04) comp-5
So these are GNU extensions ?
I would presume they are little endian on X86 hardware.
COBOL C
BINARY-CHAR UNSIGNED unsigned char
BINARY-CHAR [ SIGNED ] signed char
BINARY-SHORT UNSIGNED unsigned short
BINARY-SHORT [ SIGNED ] short
BINARY-LONG UNSIGNED unsigned long
BINARY-LONG [ SIGNED ] long
BINARY-INT int
BINARY-C-LONG [ SIGNED ] long
BINARY-DOUBLE UNSIGNED unsigned long long
BINARY-DOUBLE [ SIGNED ] long long
BINARY-LONG-LONG long lon
Last edit: Ralph Linkletter 2024-10-07
Hi,
Try to add "SYNC" before "binary-short".
(See in GnuCOBOL Programmer’s Guide: SYNCRONIZED)
And write out the size in COBOL and also in C:
I have this result:
size of c-out-struct-grp: 49
size of mystruct3: 52
01: *** begin ***
02: +00004
03: e ╩ Ð■ ö☺ ¨☺
04: * end *
05: +0000000101
05: +0000000202
05: -0000000303
05: +0000000404
05: +0000000505
Maybe can somebody explain the size differences: 49 <-> 52.
László
Last edit: László Erdős 2024-10-07
Thank you everyone!
The only thing that helped me was SYNC by @laszloerdos
(attribute packed and changing BINARY types to COBOL equivalents - didn't).
I wish it was easier to figure out, but I'm also happy that it worked eventually :)
Code snippet below:
the only change needed was the attribute((packed)) change in the aaasub.c program
Unfortunally for me - it wasn't enough. I have now went back to attribute((packed)) in C and BINARY-INT, BINARY-SHORT without SYNC in GnuCOBOL, and I still have the issue this way, including (due to?) difference in structure size (COBOL 48 bytes vs C 49 bytes) 🤷♂️
The URL that Chuck included previously answers your "due to ? ) - does it not.
https://www.tutorialspoint.com/cprogramming/c_structure_padding_and_packing.htm
I wonder if your COBOL structure passed a redefines of the binary fields as character.
That is:
77 item-amnt binary-int.
77 item-amnt-char redefines item-amnt pic x(04).
move 5 to item-amnt
COBOL would be indifferent to the type cast
Would "C" insist on padding a char field?
Is it that "C" would pad any data field of an odd length - even char ?
The value contained in a four byte field is universal - irrespective of the description.
I have finally managed to understand how 48 bytes structure transforms into 52 bytes (this is well aligned with x86_64 ABI documentation, specifically - c structure padding):
So, what I've learned is:
1. COBOL has nothing to do with this behavior
2. the arch of the machine is important (Captain-Obvious moment)
3. order of members inside c structure is important
4. from COBOL perspective the "issue" can be easily solved by FILLERs (tested), but it will make the source code non-portable
5. right way to share structure between COBOL and C is:
__attribute__((packed)) + SYNC
Hello,
from the testing which I did, the COBOL source code did not require any changes and the C code only needed to add attribute((packed)).
I did not use SYNC anywhere in my test code.
Chuck-
I saw what you did with the code and I used AI to help understand it. Thank you for the cool tutorial on how to pack so that the code is portable across architectures.
Have cool day,
jim
Sent with Proton Mail secure email.
On Thursday, October 10th, 2024 at 7:27 PM, Chuck H. chaat@users.sourceforge.net wrote:
Hello, Chuck.
You're only 50% right according to my testing :))
It seems that older version of GnuCOBOL doesn't handle packed C-structure correctly.
This problematic version is distributed with OpenCobolIDE 4.7.6 - not able to sync without SYNC keyword:
On the other hand this version (below) does not require SYNC keyword (like you've said earlier - only needs 'attribute packed' in the C-code):
Thank you for your feedback.
Sent with Proton Mail secure email.