Ada Programming/Interfacing

Ada. Time-tested, safe and secure.
Ada. Time-tested, safe and secure.

Interfacing edit

Ada is one of the few languages where interfacing is part of the language standard. The programmer can interface with other programming languages, or with the hardware.

Other programming languages edit

The language standard defines the interfaces for C, Cobol and Fortran. Of course any implementation might define further interfaces — GNAT for example defines an interface to C++.

Interfacing with other languages is actually provided by pragma Export, Import and Convention.

Interfacing with C edit

The package Interfaces.C is used to define C types. C function wrappers should be used to encapsulate types and functions on the C side. This way the code is portable and forward-compatible. This is similar to the way of interfacing with C in Java's JNI. Wrappers should be used for:

  • Translating typedefs defined in C includes to types defined in Interfaces.C;
  • Using macros and exposing macro values to the Ada side;
  • Using variable parameter list functions;
  • Defining multiple function wrappers for a function that takes weakly typed parameters such as a function that takes a char_array or a null pointer;
  • Using getters and setters for C structs that depend on operating system version or other compile-type aspect;
  • Using pointer arithmetic;
  • Keeping Ada source memory-safe.

Example edit

with Interfaces.C;
with System;
with Ada.Text_IO;

procedure Main is
   procedure W32_Open_File_Dialog
      package C renames Interfaces.C;
      use C;
      type OPENFILENAME is new System.Address;
      type Window_Type is new System.Address;
      function GetOpenFileName (p : OPENFILENAME) return;
      pragma Import (C, GetOpenFileName, "ada_getopenfilename");
      function Allocate return OPENFILENAME with
        Import => True,
        Convention => C,
        External_Name => "ofn_allocate";
      procedure Set_Struct_Size (X : OPENFILENAME) with
        Import => True,
        Convention => C,
        External_Name => "ofn_set_struct_size";
      procedure Set_Owner (X : OPENFILENAME; Owner : Window_Type) with
        Import => True,
        Convention => C,
        External_Name => "ofn_set_owner";
      procedure Set_File (X : OPENFILENAME; File : char_array; Length : with
        Import => True,
        Convention => C,
        External_Name => "ofn_set_file";
      procedure Set_Filter (X : OPENFILENAME; Filter : char_array);
      pragma Import (C, Set_Filter, "ofn_set_filter");
      procedure Set_Filter_Index (X : OPENFILENAME; N : with
        Import => True,
        Convention => C,
        External_Name => "ofn_set_filter_index";
      function Get_File (X : OPENFILENAME) return System.Address;
      pragma Import (C, Get_File, "ofn_get_file");
      function Get_File_Length (X : OPENFILENAME) return C.size_t;
      pragma Import (C, Get_File_Length, "ofn_get_file_length");
      procedure Free (X : OPENFILENAME) with
        Import => True,
        Convention => C,
        External_Name => "ofn_free";
      Ret :;
      File : aliased C.char_array := "test.txt" & C.nul;
      Filter : aliased C.char_array := "All" & C.nul & "*.*" & C.nul & C.nul & C.nul;
      OFN := Allocate;
      Set_Struct_Size (OFN);
      Set_Owner (OFN, Window_Type (System.Null_Address));
      Set_File (OFN, File, 256);
      Set_Filter (OFN, Filter);
      Set_Filter_Index (OFN, 0);
      Ret := GetOpenFileName (OFN);
      if Ret = 0 then
         Free (OFN);
         Ada.Text_IO.Put_Line ("No file selected.");
      end if;
         Selected_File_Address : System.Address := Get_File (OFN);
         Selected_File_Length : C.size_t := Get_File_Length (OFN);
         Selected_File : char_array (1 .. Selected_File_Length + 1);
         for Selected_File'Address use Selected_File_Address;
         Ada.Text_IO.Put_Line (To_Ada (Selected_File, Trim_Nul => True));
      Free (OFN);
   end W32_Open_File_Dialog;
end Main;

#include <windows.h>
#include <stdlib.h>

OPENFILENAME *ofn_allocate()
    ofn = (OPENFILENAME *) malloc(sizeof(OPENFILENAME));
    if (ofn == NULL)
        return NULL;
    memset(ofn, 0, sizeof(OPENFILENAME));
    return ofn;

void ofn_set_struct_size(OPENFILENAME *ofn)
    ofn->lStructSize = sizeof(OPENFILENAME);

void ofn_set_owner(OPENFILENAME *ofn, void *owner)
    ofn->hwndOwner = (HWND) owner;

void ofn_set_file(OPENFILENAME *ofn, char *file, int length)
    if (ofn->lpstrFile)
    ofn->lpstrFile = (char *)malloc (length);
    if (ofn->lpstrFile == NULL) {
        ofn->nMaxFile = 0;
    strncpy(ofn->lpstrFile, file, length);
    ofn->nMaxFile = length;

void ofn_set_filter(OPENFILENAME *ofn, char *filter)
    ofn->lpstrFilter = filter;

void ofn_set_filter_index(OPENFILENAME *ofn, int n)
    ofn->nFilterIndex = n;

void ofn_free(OPENFILENAME *ofn)
    if (ofn->lpstrFile)

int ada_getopenfilename(OPENFILENAME *ofn)
    return (int) GetOpenFileNameA(ofn);

char *ofn_get_file(OPENFILENAME *ofn)
    return ofn->lpstrFile;

size_t ofn_get_file_length(OPENFILENAME *ofn)
    return (size_t) lstrlen (ofn->lpstrFile);

The following project file (getopenfilename.gpr) shows how to link to comdlg32.dll:

project Getopenfilename is
   for Languages use ("Ada", "C");
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");

   package Linker is
      for Default_Switches ("ada") use ("-lComdlg32");
   end Linker;
end Getopenfilename;

Hardware devices edit

Embedded programmers usually have to write device drivers. Ada provides extensive support for interfacing with hardware, like using representation clauses to specify the exact representation of types used by the hardware, or standard interrupt handling for writing Interrupt service routines.

See also edit

Wikibook edit

Ada Reference Manual edit

Ada 95 Rationale edit

Ada Quality and Style Guide edit