Welcome Serena Central users! CLICK HERE
The migration of the Serena Central community is currently underway. Be sure to read THIS MESSAGE to get your new login set up to access your account.
beversoftware Absent Member.
Absent Member.
1999 views

Call C function using double parameters

Jump to solution

We're trying to call the following C function from COBOL:

unsigned int MagickSetResolution( MagickWand *wand, const double x_resolution,
                                  const double y_resolution );

This function is part of the GraphicsMagick Wand API. The problem is in the 'double' parameters. It's not possible to CALL using a variable declared as USAGE IS DOUBLE, this gives the following compiler error:

BY VALUE parameter WWK-RES-X illegal type

We tried a variety of different options, including PIC X(8) COMP-N, but nothing seems to work. Is calling this function even possible?

N.B. we're using the 32 bit runtime.

0 Likes
3 Solutions

Accepted Solutions
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. Luckily we found a solution to this problem ourselves. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter into to 32 bit vars and calling the function with 4 instead of 2 parameters.

The code is now like this:

           MOVE 96                       TO wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-cnv-bytes

             BY REFERENCE wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-1

             BY REFERENCE wwk-cnv-bytes-1

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-2

             BY REFERENCE wwk-cnv-bytes-2

           CALL "MagickSetImageResolution" USING

             BY VALUE h-magick-wand2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             GIVING wwk-magick-pass-fail

With the following working storage definition:

     01 wwk-cnv-double

                USAGE IS DOUBLE.

     01 wwk-cnv-bytes.

         03 wwk-cnv-bytes-1  PIC  X(4).

         03 wwk-cnv-bytes-2  PIC  X(4).

     77 wwk-resolution-1 PIC  X(4)

                USAGE IS COMP-N.

     77 wwk-resolution-2 PIC  X(4)

                USAGE IS COMP-N.

This solution was actually triggered by a comment in callc.c (see lib folder) saying that on 16 bit systems two parameters are needed to pass a 'long' or 'pointer'. Apparently this also apples to 32 bit systems.

View solution in original post

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. We did find a solution to this problem after all. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter ourselves and calling the function with 4 instead of 2 parameters.

The code is now like this:

           MOVE 96                       TO wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-cnv-bytes

             BY REFERENCE wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-1

             BY REFERENCE wwk-cnv-bytes-1

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-2

             BY REFERENCE wwk-cnv-bytes-2

           CALL "MagickSetImageResolution" USING

             BY VALUE h-magick-wand2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             GIVING wwk-magick-pass-fail

With the following working storage definition:

      01 wwk-cnv-double

                 USAGE IS DOUBLE.

      01 wwk-cnv-bytes.

          03 wwk-cnv-bytes-1  PIC  X(4).

          03 wwk-cnv-bytes-2  PIC  X(4).

      77 wwk-resolution-1 PIC  X(4)

                 USAGE IS COMP-N.

      77 wwk-resolution-2 PIC  X(4)

                 USAGE IS COMP-N.

This solution was triggered by a comment in call.c (see lib folder) stating that to pass a long parameter on 16-bit systems you need to code two parameters.

Apparently this also works for 32-bit systems.

View solution in original post

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. We did find a solution to this problem after all. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter ourselves and calling the function with 4 instead of 2 parameters.

The code is now like this:

            MOVE 96                       TO wwk-cnv-double
            
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-cnv-bytes
              BY REFERENCE wwk-cnv-double
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-resolution-1
              BY REFERENCE wwk-cnv-bytes-1
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-resolution-2
              BY REFERENCE wwk-cnv-bytes-2

            CALL "MagickSetImageResolution" USING
              BY VALUE h-magick-wand2
              BY VALUE wwk-resolution-1
              BY VALUE wwk-resolution-2
              BY VALUE wwk-resolution-1
              BY VALUE wwk-resolution-2
              GIVING wwk-magick-pass-fail

With the following working storage definition:

       01 wwk-cnv-double
                  USAGE IS DOUBLE.
       01 wwk-cnv-bytes.
           03 wwk-cnv-bytes-1  PIC  X(4).
           03 wwk-cnv-bytes-2  PIC  X(4).
       77 wwk-resolution-1 PIC  X(4)
                  USAGE IS COMP-N.
       77 wwk-resolution-2 PIC  X(4)
                  USAGE IS COMP-N.
                  
This solution was triggered by a comment in call.c (see lib folder) stating that to pass a long parameter on 16-bit systems you need to code two parameters.
Apparently this also works for 32-bit systems.

View solution in original post

0 Likes
9 Replies
Chuck Edgin Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Try using either USAGE SIGNED-LONG  or PIC S9(18) COMP-5.

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thanks for your reply. Unfortunately both options don't work for us.

It seems like only the first 4 bytes of the parameter are sent to the C function, even when explicitly using PIC X(8) COMP-N (which is 8 bytes, and shows up correctly in the debugger's 'Display in hex' function).

Can you confirm whether it's actually possible to call C-functions with 64-bit parameters when using the 32 bit runtime? Thanks.

0 Likes
Micro Focus Expert
Micro Focus Expert

RE: Call C function using double parameters

Jump to solution

That can't be right. C's double is a floating-point type - usually a 64-bit floating-point value, though C99 only requires that double be a real floating-point type, and that the range of float be a subset of the range of double, and that of double be a subset of the range of long double. (N.B. Not necessarily a proper subset.

In any case, though, while some integer type such as S9(18) COMP-5 might have the correct size, it won't have the correct representation to match C's double.

In MF COBOL, you'd use COMP-2 or (equivalently) FLOAT-LONG. I don't know about ACU.

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

We're on a regular Windows system, so I assume the double type is 64 bit double precision like usual.

ACUCOBOL has a special USAGE IS FLOAT / USAGE IS DOUBLE syntax which replaces COMP-2. This is the obvious choice, but these types are not supported in C function calls (as detailed in my first post).

So you're right, but the way we've been trying to use X(8) COMP-N (64 bit integer) is by using a value that has the same bit representation as the double we need (it's just a fixed number - 96). That number is 4636455816377925632.

I checked the value in the debugger, it does have the exact same hex value as 96 double. But it still doesn't work. After testing with a custom C function that just writes out the passed values to a text file I'm starting to think ACUCOBOL just passes the first 32 bits. This is what I'd like to see confirmed from someone who knows...

It seems like there's just no way for this to work, so we'll have to find some other way around it.

0 Likes
mhanson Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

The CALL documentation says:

"You may pass floating-point data to subroutines normally with the CALL verb. Note that you may not pass a floating-point item BY VALUE. This restriction exists for portability reasons (some machines pass floating-point using a convention different from that used for integer items). You should pass floating-point items BY REFERENCE. This will pass a pointer to the item, which the receiving routine can then retrieve by "de-referencing" the pointer."

I tried to fake out CALL by redefining my USAGE DOUBLE to another type, as you did, without any luck.  My guess is that we are running into this different parameter convention for floating point data items.  My suggestion is to write a shim C function that takes pointers to double and then calls the actual function.

0 Likes
Micro Focus Contributor
Micro Focus Contributor

RE: Call C function using double parameters

Jump to solution

There is no way to call this function without adding some extra C code somewhere. You can either relink the runtime (not recommended) or create a new DLL that will be your wrapper around this function.

Once you decide to write a new function, you can pass the double value as a pointer (by reference), or use a SUB85-style interface and do your own conversion.

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. Luckily we found a solution to this problem ourselves. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter into to 32 bit vars and calling the function with 4 instead of 2 parameters.

The code is now like this:

           MOVE 96                       TO wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-cnv-bytes

             BY REFERENCE wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-1

             BY REFERENCE wwk-cnv-bytes-1

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-2

             BY REFERENCE wwk-cnv-bytes-2

           CALL "MagickSetImageResolution" USING

             BY VALUE h-magick-wand2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             GIVING wwk-magick-pass-fail

With the following working storage definition:

     01 wwk-cnv-double

                USAGE IS DOUBLE.

     01 wwk-cnv-bytes.

         03 wwk-cnv-bytes-1  PIC  X(4).

         03 wwk-cnv-bytes-2  PIC  X(4).

     77 wwk-resolution-1 PIC  X(4)

                USAGE IS COMP-N.

     77 wwk-resolution-2 PIC  X(4)

                USAGE IS COMP-N.

This solution was actually triggered by a comment in callc.c (see lib folder) saying that on 16 bit systems two parameters are needed to pass a 'long' or 'pointer'. Apparently this also apples to 32 bit systems.

View solution in original post

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. We did find a solution to this problem after all. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter ourselves and calling the function with 4 instead of 2 parameters.

The code is now like this:

           MOVE 96                       TO wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-cnv-bytes

             BY REFERENCE wwk-cnv-double

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-1

             BY REFERENCE wwk-cnv-bytes-1

           CALL "C$MEMCPY" USING

             BY REFERENCE wwk-resolution-2

             BY REFERENCE wwk-cnv-bytes-2

           CALL "MagickSetImageResolution" USING

             BY VALUE h-magick-wand2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             BY VALUE wwk-resolution-1

             BY VALUE wwk-resolution-2

             GIVING wwk-magick-pass-fail

With the following working storage definition:

      01 wwk-cnv-double

                 USAGE IS DOUBLE.

      01 wwk-cnv-bytes.

          03 wwk-cnv-bytes-1  PIC  X(4).

          03 wwk-cnv-bytes-2  PIC  X(4).

      77 wwk-resolution-1 PIC  X(4)

                 USAGE IS COMP-N.

      77 wwk-resolution-2 PIC  X(4)

                 USAGE IS COMP-N.

This solution was triggered by a comment in call.c (see lib folder) stating that to pass a long parameter on 16-bit systems you need to code two parameters.

Apparently this also works for 32-bit systems.

View solution in original post

0 Likes
beversoftware Absent Member.
Absent Member.

RE: Call C function using double parameters

Jump to solution

Thans for your suggestions. We did find a solution to this problem after all. Apparently, calling a 64 bit parameter in x86 involves two 32 bit values being pushed on the stack. We used this to our advantage by splitting the parameter ourselves and calling the function with 4 instead of 2 parameters.

The code is now like this:

            MOVE 96                       TO wwk-cnv-double
            
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-cnv-bytes
              BY REFERENCE wwk-cnv-double
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-resolution-1
              BY REFERENCE wwk-cnv-bytes-1
            CALL "C$MEMCPY" USING
              BY REFERENCE wwk-resolution-2
              BY REFERENCE wwk-cnv-bytes-2

            CALL "MagickSetImageResolution" USING
              BY VALUE h-magick-wand2
              BY VALUE wwk-resolution-1
              BY VALUE wwk-resolution-2
              BY VALUE wwk-resolution-1
              BY VALUE wwk-resolution-2
              GIVING wwk-magick-pass-fail

With the following working storage definition:

       01 wwk-cnv-double
                  USAGE IS DOUBLE.
       01 wwk-cnv-bytes.
           03 wwk-cnv-bytes-1  PIC  X(4).
           03 wwk-cnv-bytes-2  PIC  X(4).
       77 wwk-resolution-1 PIC  X(4)
                  USAGE IS COMP-N.
       77 wwk-resolution-2 PIC  X(4)
                  USAGE IS COMP-N.
                  
This solution was triggered by a comment in call.c (see lib folder) stating that to pass a long parameter on 16-bit systems you need to code two parameters.
Apparently this also works for 32-bit systems.

View solution in original post

0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.