comp.lang.ada
 help / color / mirror / Atom feed
* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00 Interfacing to C non-void procedure with "out" parameters Dr Steve Sangwine
  2000-01-14  0:00 ` Alain Le Guennec
@ 2000-01-14  0:00 ` Ted Dennison
  2000-01-14  0:00   ` Jeff Carter
  2000-01-17  0:00 ` Matthew Heaney
  2 siblings, 1 reply; 8+ messages in thread
From: Ted Dennison @ 2000-01-14  0:00 UTC (permalink / raw)


In article <387f1c30.12554815@news.rdg.ac.uk>,
  S.J.Sangwine@Reading.ac.uk (Dr Steve Sangwine) wrote:
> Can anyone shed light on the issue of interfacing between Ada95 and C
> where there is a C procedure (non-void) which returns a result *and*
> modifies some of its parameters?

Sure; It can't happen. C routines can't modify their parameters. They
are all "in".

They can of course pass in *pointers* to objects and merrily modify the
pointed-to objects. You can do that with Ada functions too.

> I have a C procedure, for which I wanted to write an Ada95 spec, and
> import the C object code using pragma Import. Since the C procedure
> has a return result, I need an Ada function (or do I?). An Ada

Yup. Unless you are using Gnat. In that cause you could use pramga
Import_Valued_Procedure (I think I got the name right, but check).
However, that will render your binding unusable to other compilers.

> function must have parameters of mode 'in', implicitly or explicity,
> yet the C procedure will modify one or more of its parameters. To be
> safe, I wrote a wrapper procedure in C which had an extra parameter,
> and called this from Ada. The wrapper procedure called the real C
> procedure and returned the return result of the real C procedure in
> the extra parameter. That way the Ada spec can be a procedure and
> everything is watertight, but it is a nuisance to have this extra,
> trivial C wrapper procedure in between.

What I typically do is interface straight to the C routine in Ada, using
access or System.Address types where appropriate. Then I write a wrapper
routine in *Ada*, that provides a nice non-pointer Ada-like interface
(with status checks converted to exceptions, etc).

For instance, suppose we have the following (made up) C routine:

   int esGetValue (int key, const int *value);

The idea being that you pass in a key and get back a value for it. The
function returns 1 on success, 0 on failure.

On the Ada side, we'd much prefer to access this routine thusly:

   Get_Failed : exception; -- raised by Get_Value when the get fails

   function Get_Value (Key : Integer) return Integer;


First you interface to the routine to create your thin binding:

   function esGetValue (Key   : in Interfaces.C.Int;
                        Value : in System.Address
                       ) return Interfaces.C.Int;
   pragma Import (C, esGetValue, "esGetValue");

Note that for the "int *" parameter I used System.Address. This is not
officially portable, but in practice works on every normal platform. You
could instead use a type instantiated from Interfaces.C.Pointers for int
to achieve theoretical portability.

Finally we create our thick binding with the desired interface.

   function Get_Value (Key : Integer) return Integer is
      Value : aliased Interfaces.C.Int;
      use type Interfaces.C.Int; -- Give access to "=" operator
   begin
      if
        esGetValue
          (Key   => Interfaces.C.Int(Key),
           Value => Value
          ) = 0
      then
         raise Get_Failed;
      end if;
      return Integer(Value);
   end Get_Value;

--
T.E.D.

http://www.telepath.com/~dennison/Ted/TED.html


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00 ` Ted Dennison
@ 2000-01-14  0:00   ` Jeff Carter
  2000-01-14  0:00     ` Ted Dennison
  0 siblings, 1 reply; 8+ messages in thread
From: Jeff Carter @ 2000-01-14  0:00 UTC (permalink / raw)


In article <85ngl3$10s$1@nnrp1.deja.com>,
  Ted Dennison <dennison@telepath.com> wrote:
> In article <387f1c30.12554815@news.rdg.ac.uk>,
> For instance, suppose we have the following (made up) C routine:
>
>    int esGetValue (int key, const int *value);
>
> The idea being that you pass in a key and get back a value for it. The
> function returns 1 on success, 0 on failure.
>
> On the Ada side, we'd much prefer to access this routine thusly:
>
>    Get_Failed : exception; -- raised by Get_Value when the get fails
>
>    function Get_Value (Key : Integer) return Integer;
>
> First you interface to the routine to create your thin binding:
>
>    function esGetValue (Key   : in Interfaces.C.Int;
>                         Value : in System.Address
>                        ) return Interfaces.C.Int;
>    pragma Import (C, esGetValue, "esGetValue");
>
> Note that for the "int *" parameter I used System.Address. This is not
> officially portable, but in practice works on every normal platform.
You
> could instead use a type instantiated from Interfaces.C.Pointers for
int
> to achieve theoretical portability.

There's no reason to use System.Address here. Use an access parameter:

function Es_Get_Value
   (Key : Interfaces.C.Int; Value : access Interfaces.C.Int)
return Interfaces.C.Int;
pragma Import (C, ...);

>
> Finally we create our thick binding with the desired interface.
>
>    function Get_Value (Key : Integer) return Integer is
>       Value : aliased Interfaces.C.Int;
>       use type Interfaces.C.Int; -- Give access to "=" operator
>    begin
>       if
>         esGetValue
>           (Key   => Interfaces.C.Int(Key),
>            Value => Value
>           ) = 0
>       then
>          raise Get_Failed;
>       end if;
>       return Integer(Value);
>    end Get_Value;

Note that the call here should not compile; Value is not of type
System.Address. With an access parameter, use Value => Value'access and
everything should be fine.
--
Jeff Carter
"Now go away or I shall taunt you a second time."
-- Monty Python and the Holy Grail


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00   ` Jeff Carter
@ 2000-01-14  0:00     ` Ted Dennison
  2000-01-15  0:00       ` Jeff Carter
  0 siblings, 1 reply; 8+ messages in thread
From: Ted Dennison @ 2000-01-14  0:00 UTC (permalink / raw)


In article <85nqaf$95o$1@nnrp1.deja.com>,
  Jeff Carter <jrcarter001@my-deja.com> wrote:
> In article <85ngl3$10s$1@nnrp1.deja.com>,
>   Ted Dennison <dennison@telepath.com> wrote:
> > First you interface to the routine to create your thin binding:
> >
> >    function esGetValue (Key   : in Interfaces.C.Int;
> >                         Value : in System.Address
> >                        ) return Interfaces.C.Int;
> >    pragma Import (C, esGetValue, "esGetValue");
> There's no reason to use System.Address here. Use an access parameter:

If you mean doing a "Value : access Interfaces.C.Int", that is sometimes
doable. The problem with that is than many C interfaces, particularly
system calls, have optional pointer parameters where "null" is an
acceptable value. An access parameter does not allow "null" to be passed
in. So in general they aren't always useful

> >         esGetValue
> >           (Key   => Interfaces.C.Int(Key),
> >            Value => Value
> >           ) = 0
>
> Note that the call here should not compile; Value is not of type

Yikes! You're right. It should read:
esGetValue
  (Key   => Interfaces.C.Int(Key),
   Value => Value'address
  ) = 0

--
T.E.D.

http://www.telepath.com/~dennison/Ted/TED.html


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Interfacing to C non-void procedure with "out" parameters
@ 2000-01-14  0:00 Dr Steve Sangwine
  2000-01-14  0:00 ` Alain Le Guennec
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Dr Steve Sangwine @ 2000-01-14  0:00 UTC (permalink / raw)


Can anyone shed light on the issue of interfacing between Ada95 and C
where there is a C procedure (non-void) which returns a result *and*
modifies some of its parameters?

The LRM, Appendix B doesn't say anything about this, and neither does
the Ada95 Rationale as far as I can see.

I have a C procedure, for which I wanted to write an Ada95 spec, and
import the C object code using pragma Import. Since the C procedure
has a return result, I need an Ada function (or do I?). An Ada
function must have parameters of mode 'in', implicitly or explicity,
yet the C procedure will modify one or more of its parameters. To be
safe, I wrote a wrapper procedure in C which had an extra parameter,
and called this from Ada. The wrapper procedure called the real C
procedure and returned the return result of the real C procedure in
the extra parameter. That way the Ada spec can be a procedure and
everything is watertight, but it is a nuisance to have this extra,
trivial C wrapper procedure in between.

Would it work to allow the C procedure to modify a parameter that
the Ada code thinks is read-only (i.e. 'in'), or should I play safe as
described above. (By 'work', I mean work portably, not work when
compiled with a specific compiler.)

Since C programmers routinely confuse the concepts of procedure and
function (rant ....) this issue arises with almost any C code that one
wants to interface to Ada.

Dr Steve Sangwine
Division of Electronic Engineering
The University of Reading, UK
http://www.elec.rdg.ac.uk/sjs.html





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00 Interfacing to C non-void procedure with "out" parameters Dr Steve Sangwine
@ 2000-01-14  0:00 ` Alain Le Guennec
  2000-01-14  0:00 ` Ted Dennison
  2000-01-17  0:00 ` Matthew Heaney
  2 siblings, 0 replies; 8+ messages in thread
From: Alain Le Guennec @ 2000-01-14  0:00 UTC (permalink / raw)


S.J.Sangwine@Reading.ac.uk (Dr Steve Sangwine) writes:

> Can anyone shed light on the issue of interfacing between Ada95 and C
> where there is a C procedure (non-void) which returns a result *and*
> modifies some of its parameters?
> 
> The LRM, Appendix B doesn't say anything about this, and neither does
> the Ada95 Rationale as far as I can see.
> 
> I have a C procedure, for which I wanted to write an Ada95 spec, and
> import the C object code using pragma Import. Since the C procedure
> has a return result, I need an Ada function (or do I?).

If you use GNAT, you can use the pragma "Import_Valued_Procedure".
You then don't need an Ada function.
A procedure with a first OUT parameter will work.
See the GNAT Reference Manual for more information.
An excerpt follows:

`pragma Import_Valued_Procedure ...'
     Syntax:

          pragma Import_Valued_Procedure (
               [Internal                 =>] LOCAL_NAME,
            [, [External                 =>] EXTERNAL_SYMBOL]
            [, [Parameter_Types          =>] PARAMETER_TYPES]
            [, [Mechanism                =>] MECHANISM]
            [, [First_Optional_Parameter =>] IDENTIFIER]);

          EXTERNAL_SYMBOL ::=
            IDENTIFIER
          | static_string_EXPRESSION

          PARAMETER_TYPES ::=
            null
          | SUBTYPE_MARK {, SUBTYPE_MARK}

          MECHANISM ::=
            MECHANISM_NAME
          | (MECHANISM_ASSOCIATION {, MECHANISM_ASSOCIATION})

          MECHANISM_ASSOCIATION ::=
            [formal_parameter_NAME =>] MECHANISM_NAME

          MECHANISM_NAME ::=
            Value
          | Reference
          | Descriptor [([Class =>] CLASS_NAME)]

          CLASS_NAME ::= ubs | ubsb | uba | s | sb | a | nca

     This pragma is identical to `Import_Procedure' except that the
     first parameter of LOCAL_NAME, which must be present, must be of
     mode `OUT', and externally the subprogram is treated as a function
     with this parameter as the result of the function. The purpose of
     this capability is to allow the use of `OUT' and `IN OUT'
     parameters in interfacing to external functions (which are not
     permitted in Ada functions).  You may optionally use the
     `Mechanism' parameters to specify passing mechanisms for the
     parameters.  If you specify a single mechanism name, it applies to
     all parameters.  Otherwise you may specify a mechanism on a
     parameter by parameter basis using either positional or named
     notation. If the mechanism is not specified, the default mechanism
     is used.

> An Ada function must have parameters of mode 'in', implicitly or explicity,
> yet the C procedure will modify one or more of its parameters. To be
> safe, I wrote a wrapper procedure in C which had an extra parameter,
> and called this from Ada. The wrapper procedure called the real C
> procedure and returned the return result of the real C procedure in
> the extra parameter. That way the Ada spec can be a procedure and
> everything is watertight, but it is a nuisance to have this extra,
> trivial C wrapper procedure in between.
> 
> Would it work to allow the C procedure to modify a parameter that
> the Ada code thinks is read-only (i.e. 'in'), or should I play safe as
> described above. (By 'work', I mean work portably, not work when
> compiled with a specific compiler.)
> 
> Since C programmers routinely confuse the concepts of procedure and
> function (rant ....) this issue arises with almost any C code that one
> wants to interface to Ada.
> 
> Dr Steve Sangwine
> Division of Electronic Engineering
> The University of Reading, UK
> http://www.elec.rdg.ac.uk/sjs.html

Hope this helps,

-- 
	Alain Le Guennec, not speaking for IRISA.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00     ` Ted Dennison
@ 2000-01-15  0:00       ` Jeff Carter
  0 siblings, 0 replies; 8+ messages in thread
From: Jeff Carter @ 2000-01-15  0:00 UTC (permalink / raw)


In article <85nurq$cr0$1@nnrp1.deja.com>,
  Ted Dennison <dennison@telepath.com> wrote:
> In article <85nqaf$95o$1@nnrp1.deja.com>,
>   Jeff Carter <jrcarter001@my-deja.com> wrote:
> > In article <85ngl3$10s$1@nnrp1.deja.com>,
> >   Ted Dennison <dennison@telepath.com> wrote:
> > > First you interface to the routine to create your thin binding:
> > >
> > >    function esGetValue (Key   : in Interfaces.C.Int;
> > >                         Value : in System.Address
> > >                        ) return Interfaces.C.Int;
> > >    pragma Import (C, esGetValue, "esGetValue");
> > There's no reason to use System.Address here. Use an access
parameter:
>
> If you mean doing a "Value : access Interfaces.C.Int", that is
sometimes
> doable. The problem with that is than many C interfaces, particularly
> system calls, have optional pointer parameters where "null" is an
> acceptable value. An access parameter does not allow "null" to be
passed
> in. So in general they aren't always useful

This is sometimes the case, though it doesn't appear to be so here.
When it is the case, and you want to pass null, use an access type

type Int_Ptr is access all Interfaces.C.Int;

...

Value : in Int_Ptr; -- in function specification

...

Value => null -- in function call

System.Address loses all type checking. You can pass the address of
_anything_. An access parameter or access type limits you to the
address of something of the correct type. System.Address is best used
when the type is unknown, such as "void*".

--
Jeff Carter
"Now go away or I shall taunt you a second time."
-- Monty Python and the Holy Grail


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-14  0:00 Interfacing to C non-void procedure with "out" parameters Dr Steve Sangwine
  2000-01-14  0:00 ` Alain Le Guennec
  2000-01-14  0:00 ` Ted Dennison
@ 2000-01-17  0:00 ` Matthew Heaney
  2000-01-18  0:00   ` Dr Steve Sangwine
  2 siblings, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 2000-01-17  0:00 UTC (permalink / raw)


In article <387f1c30.12554815@news.rdg.ac.uk> , 
S.J.Sangwine@Reading.ac.uk (Dr Steve Sangwine) wrote:

> Can anyone shed light on the issue of interfacing between Ada95 and C
> where there is a C procedure (non-void) which returns a result *and*
> modifies some of its parameters?

In neither Ada nor C can you directly modify a function parameter.  In
both languages you have to pass a pointer to the data, and modify the
data designated by the pointer.

Given this C header:

int op (float *o);

You can bind to it from Ada like this

with Interfaces.C;  use Interfaces.C;
package P is

  type Float_Access is access all C_Float;
  pragma Convention (C, Float_Access);

  function Op (O : Float_Access) return Int;

  pragma Import (C, Op, "op");

end P;



> The LRM, Appendix B doesn't say anything about this, and neither does
> the Ada95 Rationale as far as I can see.

There's nothing magic about the fact that the C procedure has a non-void
return value.  Just import the C procedure as an Ada function.


> I have a C procedure, for which I wanted to write an Ada95 spec, and
> import the C object code using pragma Import. Since the C procedure
> has a return result, I need an Ada function (or do I?).

Yes.  Unless you want to throw away the procedure's return value, in
which case you can bind to it using an Ada procedure.


> An Ada
> function must have parameters of mode 'in', implicitly or explicity,
> yet the C procedure will modify one or more of its parameters.

It's impossible for C to modify a parameter.

Actually, I should qualify the above statement.  In C, you can modify a
parameter, for use as a local variable.  However, any changes you make
to the value of the parameter remain local, and are not transmitted back
to the caller.

The only way to modify a caller's value is the pass the address of the
object to a C procedure.

> To be
> safe, I wrote a wrapper procedure in C which had an extra parameter,
> and called this from Ada. The wrapper procedure called the real C
> procedure and returned the return result of the real C procedure in
> the extra parameter. That way the Ada spec can be a procedure and
> everything is watertight, but it is a nuisance to have this extra,
> trivial C wrapper procedure in between.

It's a nuisance, and unnecessary.  Get rid of it.


> Would it work to allow the C procedure to modify a parameter that
> the Ada code thinks is read-only (i.e. 'in'), or should I play safe as
> described above. (By 'work', I mean work portably, not work when
> compiled with a specific compiler.)


You are free to modify a parameter on the C side that Ada thinks is in,
just as can with a C caller.  However, these changes are not propagated
back to the Ada client, nor to a C client.


> Since C programmers routinely confuse the concepts of procedure and
> function (rant ....) this issue arises with almost any C code that one
> wants to interface to Ada.

There is no issue.


--
You cannot think without abstractions; accordingly, it is of the utmost
importance to be vigilant in critically revising your modes of
abstraction.  It is here that philosophy finds its niche as essential to
the healthy progress of society.  It is the critic of abstractions.

Alfred North Whitehead




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Interfacing to C non-void procedure with "out" parameters
  2000-01-17  0:00 ` Matthew Heaney
@ 2000-01-18  0:00   ` Dr Steve Sangwine
  0 siblings, 0 replies; 8+ messages in thread
From: Dr Steve Sangwine @ 2000-01-18  0:00 UTC (permalink / raw)


On Mon, 17 Jan 2000 16:58:55 GMT, "Matthew Heaney"
<matthew_heaney@acm.org> wrote:

>In neither Ada nor C can you directly modify a function parameter.  In
>both languages you have to pass a pointer to the data, and modify the
>data designated by the pointer.

>You are free to modify a parameter on the C side that Ada thinks is in,
>just as can with a C caller.  However, these changes are not propagated
>back to the Ada client, nor to a C client.

Thanks for this, and to Ted Dennison for his comments. This has
clarified the position greatly.

Dr Steve Sangwine
Division of Electronic Engineering
The University of Reading, UK
http://www.elec.rdg.ac.uk/sjs.html





^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2000-01-18  0:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-01-14  0:00 Interfacing to C non-void procedure with "out" parameters Dr Steve Sangwine
2000-01-14  0:00 ` Alain Le Guennec
2000-01-14  0:00 ` Ted Dennison
2000-01-14  0:00   ` Jeff Carter
2000-01-14  0:00     ` Ted Dennison
2000-01-15  0:00       ` Jeff Carter
2000-01-17  0:00 ` Matthew Heaney
2000-01-18  0:00   ` Dr Steve Sangwine

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox