Call a foreign-language function

From Rosetta Code
Revision as of 21:52, 23 October 2011 by rosettacode>Mischi (add link to Delphi for pascal)
Task
Call a foreign-language function
You are encouraged to solve this task according to the task description, using any language you may know.

Show how a foreign language function can be called from the language.

As an example, consider calling functions defined in the C language. Create a string containing "Hello World!" of the string type typical to the language. Pass the string content to C's strdup. The content can be copied if necessary. Get the result from strdup and print it using language means. Do not forget to free the result of strdup (allocated in the heap).

Notes:

  • It is not mandated if the C run-time library is to be loaded statically or dynamically. You are free to use either way.
  • C++ and C solutions can take some other language to communicate with.
  • It is not mandatory to use strdup, especially if the foreign function interface being demonstrated makes that uninformative.

See also:

Ada

Ada provides standard interfaces to C, C++, Fortran and Cobol. Other language interfaces can be provided as well, but are not mandatory. Usually it is possible to communicate to any language that supports calling conventions standard to the OS (cdecl, stdcall etc). <lang Ada>with Ada.Text_IO; use Ada.Text_IO; with Interfaces.C; use Interfaces.C; with Interfaces.C.Strings; use Interfaces.C.Strings;

procedure Test_C_Interface is

  function strdup (s1 : Char_Array) return Chars_Ptr;
  pragma Import (C, strdup, "_strdup");
  S1 : constant String := "Hello World!";
  S2 : Chars_Ptr;

begin

  S2 := strdup (To_C (S1));
  Put_Line (Value (S2));
  Free (S2);

end Test_C_Interface;</lang>

Aikido

There are two ways to call a native function in Aikido. The first is to write a wrapper function in C++ that is invoked from the Aikido interpreter. In a C++ file: <lang aikido>#include <aikido.h> extern "C" { // need C linkage

// define the function using a macro defined in aikido.h AIKIDO_NATIVE(strdup) {

   aikido::string *s = paras[0].str;
   char *p = strdup (s->c_str());
   aikido::string *result = new aikido::string(p);
   free (p);
   return result;

}

}</lang>

Then in the Aikido program: <lang aikido>native function strdup(s) println (strdup ("Hello World!"))</lang>

The second way is to use a raw native function. These functions must adhere to a defined set of rules and can be called directly from the Aikido interpreter. In the case of strdup we need to play a nasty trick because it returns a pointer that we need to print as a string.

<lang aikido>native function strdup (s) // declare native native function free(p) // also need to free the result

var s = strdup ("hello world\n") var p = s // this is an integer type for (;;) {

   var ch = peek (p, 1)   // read a single character 
   if (ch == 0) {
       break
   }
   print (cast<char>(ch))   // print as a character
   p++

} free (s) // done with the memory now</lang>

AutoHotkey

from the documentation for dllcall: <lang AutoHotkey>; Example: Calls the Windows API function "MessageBox" and report which button the user presses.

WhichButton := DllCall("MessageBox", "int", "0", "str", "Press Yes or No", "str", "Title of box", "int", 4) MsgBox You pressed button #%WhichButton%.</lang>

C++

While calling C functions from C++ is generally almost trivial, strdup illustrates some fine point in communicating with C libraries. However, to illustrate how to generally use C functions, a C function strdup1 is used, which is assumed to have the same interface and behaviour as strdup, but cannot be found in a standard header.

In addition, this code demonstrates a call to a FORTRAN function defined as <lang cpp>FUNCTION MULTIPLY(X, Y) DOUBLE PRECISION MULTIPLY, X, Y</lang> Note that the calling convention of FORTRAN depends on the system and the used FORTRAN compiler, and sometimes even on the command line options used for the compiler; here, GNU Fortran with no options is assumed. <lang cpp>#include <cstdlib> // for C memory management

  1. include <string> // for C++ strings
  2. include <iostream> // for output

// C functions must be defined extern "C" extern "C" char* strdup1(char const*);

// Fortran functions must also be defined extern "C" to prevent name // mangling; in addition, all fortran names are converted to lowercase // and get an undescore appended. Fortran takes all arguments by // reference, which translates to pointers in C and C++ (C++ // references generally work, too, but that may depend on the C++ // compiler) extern "C" double multiply_(double* x, double* y);

// to simplify the use and reduce the probability of errors, a simple // inline forwarder like this can be used: inline double multiply(double x, double y) {

 return multiply_(&x, &y);

}

int main() {

 std::string msg = "The product of 3 and 5 is ";
 // call to C function (note that this should not be assigned
 // directly to a C++ string, because strdup1 allocates memory, and
 // we would leak the memory if we wouldn't save the pointer itself
 char* msg2 = strdup1(msg.c_str());
 // C strings can be directly output to std::cout, so we don't need
 // to put it back into a string to output it.
 std::cout << msg2;
 // call the FORTRAN function (through the wrapper):
 std::cout << multiply(3, 5) << std::endl;
 // since strdup1 allocates with malloc, it must be deallocated with
 // free, not delete, nor delete[], nor operator delete
 std::free(msg2);

}</lang>

Common Lisp

Library: CFFI

<lang lisp>CL-USER> (let* ((string "Hello World!")

               (c-string (cffi:foreign-funcall "strdup" :string string :pointer)))
          (unwind-protect (write-line (cffi:foreign-string-to-lisp c-string))
            (cffi:foreign-funcall "free" :pointer c-string :void))
          (values))

Hello World!

No value</lang>

D

<lang d>import std.stdio; import std.string;

extern(C) {

   char* strdup(char* s1);
   void free(void* ptr);

}

void main() {

   // note that we could use char* here (as string literals are null-terminated)
   // but we want to comply with the "of the string type typical to the language" part
   // NOTE: D supports 0-values inside a string, C does not (as 0 terminates it)
   char[] input = "Hello World!";
   // method 1 (prefered)
   //     -> toStringz converts D strings to null-terminated C strings
   char* str1 = strdup(toStringz(input));
   // method 2
   //     -> D strings are not null-terminated, so we append that
   //     -> .ptr returns a pointer to the 1st element of the array, &input[0])
   //         -> this has to be done because D arrays internally look like this: T[] -> { size_t length; T* pointer; }
   char* str2 = strdup((input ~ '\0').ptr);
   // again, we could have just used printf, but it does says "print it using language means"
   writefln("str1: ", toString(str1));
   writefln("str2: ", toString(str2));
   free(str1);
   free(str2);

}</lang>

Delphi

Importing the function from a shared library

If you have the function to be called available as a shared library you just do an import of that function using the means as shown for calling a function from a shared library.

Object Files

There is limited support for linking a function using an object file. For this to work the object file has to be in Borland Linker compatible format. Trying to use a GCC-created object file doesn't work.

The file first has to be bound to your unit:

<lang delphi> {$O myhello.obj} </lang>

The next step is to do an external declaration for the function: <lang delphi> procedure Hello(S: PChar); stdcall; external; </lang>

Afterwards usage of the function is just as with any other function.

Factor

If you declare a parameter as c-string, Factor automatically converts NULL-terminated C strings to Factor strings and back. In this case we additionally have to free the returned string, so we have to do the conversion explicitly; else the reference to the pointer would be dropped behind the scenes.

libc is already loaded, it is used by Factor elsewhere. <lang factor>FUNCTION: char* strdup ( c-string s ) ;

my-strdup ( str -- str' )
   strdup [ utf8 alien>string ] [ (free) ] bi ;</lang>
( scratchpad ) "abc" my-strdup .
"abc"

Forth

Works with: GNU Forth version 0.7.0

Every version of GNU Forth has experimented with a different means to do C foreign function calls. The current implementation resolves various incompatibilities which had plagued earlier mechanisms by parsing C header files and using the host's native toolchain (i.e. gcc and ld) to generate thunks.

<lang forth>c-library cstrings

\c #include <string.h> c-function strdup strdup a -- a ( c-string -- duped string ) c-function strlen strlen a -- n ( c-string -- length )

end-c-library

\ convenience function (not used here)

c-string ( addr u -- addr' )
   tuck  pad swap move  pad + 0 swap c!  pad ;

create test s" testing" mem, 0 c,

test strdup value duped

test . test 7 type \ testing cr duped . \ different address duped dup strlen type \ testing

duped free throw \ gforth ALLOCATE and FREE map directly to C's malloc() and free()</lang>

Go

Using cgo, part of the standard Go command set. <lang go>package main

// #include <string.h> // #include <stdlib.h> import "C" import (

   "fmt"
   "unsafe"

)

func main() {

   // a go string
   go1 := "hello C"
   // allocate in C and convert from Go representation to C representation
   c1 := C.CString(go1)
   // go string can now be garbage collected
   go1 = ""
   // strdup, per task. this calls the function in the C library.
   c2 := C.strdup(c1)
   // free the source C string.  again, this is free() in the C library.
   C.free(unsafe.Pointer(c1))
   // create a new Go string from the C copy
   go2 := C.GoString(c2)
   // free the C copy
   C.free(unsafe.Pointer(c2))
   // demonstrate we have string contents intact
   fmt.Println(go2)

}</lang> Output:

hello C

Haskell

<lang Haskell>{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign (free) import Foreign.C.String (CString, withCString, peekCString)

-- import the strdup function itself -- the "unsafe" means "assume this foreign function never calls back into Haskell and avoid extra bookkeeping accordingly" foreign import ccall unsafe "string.h strdup" strdup :: CString -> IO CString

testC = withCString "Hello World!" -- marshall the Haskell string "Hello World!" into a C string...

       (\s -> -- ... and name it s
        do s2 <- strdup s
           s2_hs <- peekCString s2 -- marshall the C string called s2 into a Haskell string named s2_hs
           putStrLn s2_hs
           free s2) -- s is automatically freed by withCString once done</lang>

Icon and Unicon

(This probably also works for Icon, but only tested on Unicon, and on Linux.)

The first step is to create a shared library, to wrap the target C functions and do type conversions on the input and returned values. The arguments to the wrapper functions form a list, and this list must be unpacked to retrieve the arguments to send to the target function. To get at strdup and strcat we would have:

<lang C>

  1. include <string.h>
  2. include "icall.h" // a header routine from the Unicon sources - provides helpful type-conversion macros

int strdup_wrapper (int argc, descriptor *argv) {

 ArgString (1); // check that the first argument is a string
 
 RetString (strdup (StringVal(argv[1]))); // call strdup, convert and return result

}

// and strcat, for a result that does not equal the input int strcat_wrapper (int argc, descriptor *argv) {

 ArgString (1);
 ArgString (2);
 char * result = strcat (StringVal(argv[1]), StringVal(argv[2]));
 RetString (result);

} </lang>

Then the Unicon program must 'access' the function in the shared library: the important step is 'loadfunc' which accesses the named function in the shared library. After that, the C function can be called from within a program:

<lang Unicon> $define LIB "libstrdup-wrapper.so"

  1. the unicon wrapper to access the C function

procedure strdup (str)

 static f
 initial {
   f := loadfunc (LIB, "strdup_wrapper") // pick out the wrapped function from the shared library
 }
 return f(str) // call the wrapped function

end

procedure strcat (str1, str2)

 static f
 initial {
   f := loadfunc (LIB, "strcat_wrapper")
 }
 return f(str1, str2)

end

procedure main ()

 write (strdup ("abc"))
 write (strcat ("abc", "def"))

end </lang>

Output:

$ ./str-test
abc
abcdef

J

Here is a windows specific implementation (for relatively recent versions of windows):

<lang J>require 'dll' strdup=: 'msvcrt.dll _strdup >x *' cd < free=: 'msvcrt.dll free n x' cd < getstr=: free ] memr@,&0 _1</lang>

With these definitions: <lang J> getstr@strdup 'Hello World!' Hello World!</lang>

Portability is possible, but often irrelevant for a task of this sort. To make this work with a different OS, you would need to use the appropriate file name for libc for the os in question. For example, on linux, replace msvcrt.dll with /lib/libc.so.6 (or whichever version of libc you are using).

See also: J's documentation

Lisaac

Use backtick notation (`...`) for referencing foreign language (C) features. <lang Lisaac>Section Header

+ name := TEST_C_INTERFACE;

// this will be inserted in front of the program - external := `#include <string.h>`;

Section Public

- main <- (

 + s : STRING_CONSTANT;
 + p : NATIVE_ARRAY[CHARACTER];
 s := "Hello World!";
 p := s.to_external;
 // this will be inserted in-place
 // use `expr`:type to tell Lisaac what's the type of the external expression
 p := `strdup(@p)` : NATIVE_ARRAY[CHARACTER];
 s.print;
 '='.print;
 p.println;
 // this will also be inserted in-place, expression type disregarded
 `free(@p)`;

);</lang>

Modula-2

The first file (Vga.c) creates the function prototypes. <lang c>#include <vga.h>

int Initialize (void) {

  if ( vga_init () == 0 )
    return 1;
  else
    return 0;

}

void SetMode (int newmode) {

  vga_setmode (newmode);

}

int GetMode (void) {

  return vga_getcurrentmode ();

}

int MaxWidth (void) {

  return vga_getxdim ();

}

int MaxHeight (void) {

  return vga_getydim ();

}

void Clear (void) {

  vga_clear ();

} void SetColour (int colour) {

  vga_setcolor (colour);

}

void SetEGAcolour (int colour) {

  vga_setegacolor (colour);

}

void SetRGB (int red, int green, int blue) {

  vga_setrgbcolor (red, green, blue);

}

void DrawLine (int x0, int y0, int dx, int dy) {

  vga_drawline (x0, y0, x0 + dx, y0 + dy);

}

void Plot (int x, int y) {

  vga_drawpixel (x, y);

}

int ThisColour (int x, int y) {

  return vga_getpixel (x, y);

}

void GetKey (char *ch) {

  *ch = vga_getkey ();

}</lang> The next file is the definition module, but in this context it is called a FOREIGN MODULE. <lang modula2>FOREIGN MODULE Vga;

TYPE EGAcolour = (black, blue, green, cyan, red, pink, brown, white,

                      GREY, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE);

PROCEDURE Initialize () : BOOLEAN;

PROCEDURE MaxWidth () : CARDINAL;

PROCEDURE MaxHeight () : CARDINAL;

PROCEDURE Clear;

PROCEDURE SetColour (colour : CARDINAL);

PROCEDURE SetEGAcolour (colour : CARDINAL);

PROCEDURE SetRGB (red, green, blue : CARDINAL);

PROCEDURE DrawLine (x0, y0, dx, dy : CARDINAL);

PROCEDURE Plot (x, y : CARDINAL);

PROCEDURE ThisColour (x, y : CARDINAL) : CARDINAL;

PROCEDURE SetMode (newmode : CARDINAL);

PROCEDURE GetMode () : CARDINAL;

PROCEDURE GetKey (VAR ch : CHAR);

END Vga.</lang> The third file is an example program. <lang modula2>MODULE svg01;

FROM InOut IMPORT Read, Write, WriteBf, WriteString;

IMPORT Vga;

VAR OldMode, x, y  : CARDINAL;

     ch                        : CHAR;

BEGIN

  IF  Vga.Initialize () = FALSE  THEN
     WriteString ('Could not start SVGAlib libraries. Aborting...');
     WriteBf;
     HALT
  END;
  OldMode := Vga.GetMode ();
  Vga.SetMode (4);
  Vga.SetColour (14);
  Vga.Clear ();
  Vga.SetColour (10);
  FOR y := 125 TO 175 DO
     FOR x := 100 TO 500 DO
        Vga.Plot (x, y)
     END
  END;
  LOOP
     Read (ch);
     IF  ch = 'X'  THEN  EXIT  END
  END;
  Vga.SetMode (OldMode);
  Write (ch);
  WriteBf;

END svg01.</lang>

Modula-3

Modula-3 provides many predefined interfaces to C files. Here we use Cstring which uses C string functions. Note we have to convert strings of type TEXT into C strings (NULL terminated character arrays). Also note the code requires the UNSAFE keyword because it interfaces with C (which is unsafe). <lang modula3>UNSAFE MODULE Foreign EXPORTS Main;

IMPORT IO, Ctypes, Cstring, M3toC;

VAR string1, string2: Ctypes.const_char_star;

BEGIN

 string1 := M3toC.CopyTtoS("Foobar");
 string2 := M3toC.CopyTtoS("Foobar2");
 IF Cstring.strcmp(string1, string2) = 0 THEN
   IO.Put("string1 = string2\n");
 ELSE
   IO.Put("string1 # string2\n");
 END;
 M3toC.FreeCopiedS(string1);
 M3toC.FreeCopiedS(string2);

END Foreign.</lang> Output:

string1 # string2

Nimrod

Since Nimrod compiles to C by default, this task is easily done:

<lang nimrod> proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.} echo strcmp("abc", "def") echo strcmp("hello", "hello") </lang>

OCaml

Outline of what is linked against

For the hypothetical C library that contains functions described by a header file with this in: <lang ocaml>void myfunc_a(); float myfunc_b(int, float); char *myfunc_c(int *);</lang>

The header file is named "mylib.h", and linked against the library with -lmylib and compiled with -I/usr/include/mylib.

Required files

Here are provided all the files, including a Makefile.

file "mylib.ml":

<lang ocaml>external myfunc_a: unit -> unit = "caml_myfunc_a" external myfunc_b: int -> float -> float = "caml_myfunc_b" external myfunc_c: int array -> string = "caml_myfunc_c"</lang>

file "wrap_mylib.c":

<lang c>#include <caml/mlvalues.h>

  1. include <caml/alloc.h>
  2. include <mylib.h>

CAMLprim value caml_myfunc_a(value unit) {

   myfunc_a();
   return Val_unit;

}

CAMLprim value caml_myfunc_b(value a; value b) {

   float c = myfunc_b(Int_val(a), Double_val(b));
   return caml_copy_double(c);

}

CAMLprim value caml_myfunc_c(value ml_array) {

   int i, len;
   int *arr;
   char *s;
   len = Wosize_val(ml_array);
   arr = malloc(len * sizeof(int));
   for (i=0; i < len; i++) {
       arr[i] = Int_val(Field(ml_array, i));
   }
   s = myfunc_c(arr);
   free(arr);
   return caml_copy_string(s);

}</lang>

the Makefile:

<lang makefile>wrap_mylib.o: wrap_mylib.c

       ocamlc -c -ccopt -I/usr/include/mylib $<

dllmylib_stubs.so: wrap_mylib.o

       ocamlmklib -o mylib_stubs $< -lmylib

mylib.mli: mylib.ml

       ocamlc -i $< > $@

mylib.cmi: mylib.mli

       ocamlc -c $<

mylib.cmo: mylib.ml mylib.cmi

       ocamlc -c $<

mylib.cma: mylib.cmo dllmylib_stubs.so

       ocamlc -a -o $@ $< -dllib -lmylib_stubs -cclib -lmylib

mylib.cmx: mylib.ml mylib.cmi

       ocamlopt -c $<

mylib.cmxa: mylib.cmx dllmylib_stubs.so

       ocamlopt -a -o $@ $< -cclib -lmylib_stubs -cclib -lmylib

clean:

       rm -f *.[oa] *.so *.cm[ixoa] *.cmxa</lang>

the file mylib.cma is used for the interpreted and bytecode modes, and mylib.cmxa is for the native mode.

Oz

First we need to create a so-called "native functor" that converts the arguments and describes the C functions: <lang cpp>#include "mozart.h"

  1. include <string.h>

OZ_BI_define(c_strdup,1,1) {

 OZ_declareVirtualString(0, s1);
 char* s2 = strdup(s1);
 OZ_Term s3 = OZ_string(s2);
 free( s2 );
 OZ_RETURN( s3 );

} OZ_BI_end

OZ_C_proc_interface * oz_init_module(void) {

 static OZ_C_proc_interface table[] = {
   {"strdup",1,1,c_strdup},
   {0,0,0,0}
 };
 return table;

}</lang>

Save this file as "strdup.cc". To automate compiling and linking, we need a makefile for ozmake, the Oz build tool. Save this file as "makefile.oz": <lang oz>makefile(

  lib : [

'strdup.o' 'strdup.so' ]

  rules:o('strdup.so':ld('strdup.o'))
  )</lang>

Call ozmake in the same directory.

Now we can write some code that uses the wrapped C function (make sure Emacs' working directory is set to the same directory):

<lang oz>declare

 [Strdup] = {Module.link ['strdup.so{native}']}

in

 {System.showInfo {Strdup.strdup "hello"}}</lang>

PARI/GP

Of course it is trivial to include C functions in PARI, and not uncommon. In GP the system and install commands allow foreign-language functions to be called.

Pascal

See Delphi

Perl

Perl code calls a C function c_dup() passing a string 'Hello' as an argument, which gets transparently converted to a C string, the c_dup() function makes a copy of that string using strdup() function, stores pointer to the copy in the copy variable and returns it. The returned char pointer gets converted transparently to a Perl string value and gets returned to the calling Perl code which prints it. Then the Perl code calls a C function c_free() to free the allocated memory. Both of the C functions are defined inline in the Perl program and are automatically compiled (only once, unless they change) and linked at runtime. Here is the entire program: <lang perl>use Inline C => q{

   char *copy;
   char * c_dup(char *orig) {
       return copy = strdup(orig);
   }
   void c_free() {
       free(copy);
   }

}; print c_dup('Hello'), "\n"; c_free();</lang>

Another example, instead of returning the copy to Perl code it prints it using C printf: <lang perl>use Inline C => q{

   void c_hello (char *text) {
       char *copy = strdup(text);
       printf("Hello, %s!\n", copy);
       free(copy);
   }

}; c_hello 'world';</lang>

PicoLisp

The easiest is to inline the C code. Another possibility would be to write it into a separate shared object file (see "Call a function in a shared library").

There are differences between the 32-bit and 64-bit versions. While the 64-bit version can interface directly to C functions, requires the 32-bit function some glue code.

32-bit version

<lang PicoLisp>(load "@lib/gcc.l")

(gcc "str" NIL # The 'gcc' function passes all text

  'duptest )                 # until /**/ to the C compiler

any duptest(any ex) {

  any x = evSym(cdr(ex));    // Accept a symbol (string)
  char str[bufSize(x)];      // Create a buffer to unpack the name
  char *s;
  bufString(x, str);         // Upack the string
  s = strdup(str);           // Make a duplicate
  x = mkStr(s);              // Build a new Lisp string
  free(s);                   // Dispose the duplicate
  return x;

} /**/

(println 'Duplicate (duptest "Hello world!"))</lang>

64-bit version

<lang PicoLisp>(load "@lib/native.l")

(gcc "str" NIL

  (duptest (Str) duptest 'S Str) )
  1. include <stdlib.h>
  2. include <string.h>

char *duptest(char *str) {

  static char *s;
  free(s);    // We simply dispose the result of the last call
  return s = strdup(str);

} /**/

(println 'Duplicate (duptest "Hello world!"))</lang>

Output in both cases:

Duplicate "Hello world!"

PL/I

<lang>declare strdup entry (character (30) varyingz) options (fastcall16);

put (strdup('hello world') );</lang>

Python

<lang python>import ctypes libc = ctypes.CDLL("/lib/libc.so.6") libc.strcmp("abc", "def") # -1 libc.strcmp("hello", "hello") # 0</lang>

Ruby

There are three or four different approaches one can take.

By far still the most common today is writing a C binding that is compiled on installation and has to be recompiled when the underlying library changes.

Unfortunately I've never written one of these myself, maybe someone else can demonstrate it.

FFI

A recent effort to make it easier to write libraries, portable across platforms and interpreters, led to the creation of a libffi binding simply called ffi for completely dynamic calls.

<lang ruby> require 'ffi'

module LibC

 extend FFI::Library
 ffi_lib FFI::Platform::LIBC
 attach_function :strdup, [:string], :pointer
 attach_function :free, [:pointer], :void

end

string = "Hello, World!" duplicate = LibC.strdup(string) puts duplicate.get_string(0) LibC.free(duplicate) </lang>

Fiddle

Ruby 1.9.2 added Fiddle to the standard library. DL finds foreign functions, and Fiddle uses libffi to call them. DL and Fiddle are poorly documented. They are not compatible with all platforms.

Works with: MRI version 1.9.2

<lang ruby>require 'dl' require 'fiddle'

  1. Declare strdup().
  2. * DL::Handle['strdup'] is the address of the function.
  3. * The function takes a pointer and returns a pointer.

strdup = Fiddle::Function.new(DL::Handle['strdup'],

                             [DL::TYPE_VOIDP], DL::TYPE_VOIDP)
  1. Call strdup().
  2. * Fiddle converts our Ruby string to a C string.
  3. * Fiddle returns a DL::CPtr.

duplicate = strdup.call("This is a string!")

  1. DL::CPtr#to_s converts our C string to a Ruby string.

puts duplicate.to_s

  1. We must call free(), because strdup() allocated memory.

DL.free duplicate</lang>

RubyInline

Using

Library: RubyGems

package RubyInline, which compiles the inlined code on demand during runtime.

<lang ruby>require 'rubygems' require 'inline'

class InlineTester

 def factorial_ruby(n)
   (1..n).inject(1, :*)
 end
 inline do |builder|
   builder.c <<-'END_C'
     long factorial_c(int max) {
       long result = 1;
       int i;
       for (i = 1; i <= max; ++i)
         result *= i;
       return result;
     }
   END_C
 end
 
 inline do |builder|
   builder.include %q("math.h")
   builder.c <<-'END_C'
     int my_ilogb(double value) {
       return ilogb(value);
     }
   END_C
 end

end

t = InlineTester.new 11.upto(14) {|n| p [n, t.factorial_ruby(n), t.factorial_c(n)]} p t.my_ilogb(1000)</lang>

outputs (note Ruby's implicit use of Bignum past 12!, while C is stuck with a long int):

[11, 39916800, 39916800]
[12, 479001600, 479001600]
[13, 6227020800, 1932053504]
[14, 87178291200, 1278945280]
9

Tcl

Library: critcl

In this solution, we wrap up the ilogb function from C's math library with critcl so that it becomes one of Tcl's normal functions (assuming Tcl 8.5): <lang tcl>package require critcl critcl::code {

   #include <math.h>

} critcl::cproc tcl::mathfunc::ilogb {double value} int {

   return ilogb(value);

} package provide ilogb 1.0</lang> Note that we do not show strdup here because Tcl manages the memory for strings in complex ways and does not guarantee to preserve string pointers from one call into the C API to the next (e.g., if it has to apply an encoding transformation behind the scenes).