[mercury-users] Mercury and C

Fergus Henderson fjh at cs.mu.OZ.AU
Tue Nov 12 20:31:20 AEDT 2002


On 12-Nov-2002, Ralph Becket <rafe at cs.mu.OZ.AU> wrote:
> Drirr C., Monday, 11 November 2002:
> > I'm writing a program using Mercury and C, however I haven't been able to
> > return a string from the c function.
> >  
> > I have something like this:
> >  
> >  :- pred buildPoly(int::in, int::in, int::in, int::in, string::out) is det.
> >  ...
> > :- pragma c_code(buildPoly(VARS::in,TERMS::in,NEG::in,SEED::in,OUT::out),
> > [may_call_mercury], "buildPoly(VARS,TERMS,NEG,SEED,OUT);").
> >  
> >  And then something like this:
> >  
> >  void  buildPoly(MR_Integer variables, MR_Integer terms, MR_Integer
> > negations, MR_Integer seed,  MR_Word result) {
> >  ...
> >      buffer = (char*)malloc(...);
> >  ...
> >      *((char **)result) = buffer;
> > }
> 
> According to "Passing Data to and from C" in the Reference Manual
> http://www.mercury.cs.mu.oz.au/information/doc-latest/reference_manual_14.html#SEC126
> we have
> typedef MR_Char *MR_String;

Right.

> Also, we have "For output arguments, the Mercury implementation will
> pass to the C function an address in which to store the result."

That statement only applies to C functions imported using "pragma import"
(or exported using "pragma export"), not to "pragma c_code", for which
you just have a C code fragment, not a C function.
If you are using "pragma c_code", then you just assign to the output variables.

    :- pragma c_code(buildPoly(VARS::in,TERMS::in,NEG::in,SEED::in,OUT::out),
        [may_call_mercury], "OUT = buildPoly(VARS,TERMS,NEG,SEED);").
                             ^^^^^^

If you want, you can do these assignments indirectly, by passing the
addresses of the output arguments to a function, but if so, you need
to explicitly take the address:

    :- pragma c_code(buildPoly(VARS::in,TERMS::in,NEG::in,SEED::in,OUT::out),
        [may_call_mercury], "buildPoly(VARS,TERMS,NEG,SEED,&OUT);").
                                                           ^
However, if all you are doing in the `pragma c_code' is calling a
C function, then generally it's better to use `pragma import',
since that is more concise:

    :- pragma import(buildPoly(in,in,in,in,out), [may_call_mercury],
	"buildPoly").

That, together with Ralph's suggestion about using `MR_String *'
rather than `MR_Word', should solve your problem.  The suggestion
about using MR_GC_malloc() rather than malloc() is also a good idea;
it avoids a potential memory leak.

Putting all these together:

    :- pragma import(buildPoly(in,in,in,in,out), [may_call_mercury],
	"buildPoly").

    :- pragma c_header_code("
    void 
    buildPoly(MR_Integer variables, MR_Integer terms, MR_Integer negations,
        MR_Integer seed,  MR_String *result);
    ").

    :- pragma c_code("
    void 
    buildPoly(MR_Integer variables, MR_Integer terms, MR_Integer negations,
        MR_Integer seed,  MR_String *result)
    {
        char *buffer;
        ...
        buffer = (char*)MR_GC_malloc(...);
        ...
        *result = buffer;
    }
    ").

Or alternatively, you can write the C code inline, rather than
putting it in a separate C function:

    :- pragma c_code(buildPoly(VARS::in,TERMS::in,NEG::in,SEED::in,OUT::out),
        [may_call_mercury],
    "
	char *buffer;
        ...
        buffer = (char*)MR_GC_malloc(...);
        ...
        OUT = buffer;
    ").

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list