B.3 Interfacing with C and C++
{
8652/0059}
{
AI95-00131-01}
{
AI95-00376-01}
{interface to C} {C
interface} The facilities relevant to
interfacing with the C language and the corresponding subset of the C++
language are the package Interfaces.C and its children; support for the
Import, Export, and Convention pragmas with
convention_
identifier
C; and support for the Convention pragma with
convention_
identifier
C_Pass_By_Copy.
{
AI95-00376-01}
The package Interfaces.C contains the basic types, constants and subprograms
that allow an Ada program to pass scalars and strings to C and C++ functions.
When this clause mentions a C entity, the reference also applies to the
corresponding entity in C++.
Static Semantics
The library package
Interfaces.C has the following declaration:
package Interfaces.C
is
pragma Pure(C);
-- Declarations based on C's <limits.h>
CHAR_BIT :
constant :=
implementation-defined;
-- typically 8
SCHAR_MIN :
constant :=
implementation-defined;
-- typically –128
SCHAR_MAX :
constant :=
implementation-defined;
-- typically 127
UCHAR_MAX :
constant :=
implementation-defined;
-- typically 255
-- Signed and Unsigned Integers
type int
is range implementation-defined;
type short
is range implementation-defined;
type long
is range implementation-defined;
type signed_char
is range SCHAR_MIN .. SCHAR_MAX;
for signed_char'Size
use CHAR_BIT;
type unsigned
is mod implementation-defined;
type unsigned_short
is mod implementation-defined;
type unsigned_long
is mod implementation-defined;
type unsigned_char
is mod (UCHAR_MAX+1);
for unsigned_char'Size
use CHAR_BIT;
subtype plain_char
is implementation-defined;
type ptrdiff_t
is range implementation-defined;
type size_t
is mod implementation-defined;
-- Floating Point
type C_float
is digits implementation-defined;
type double
is digits implementation-defined;
type long_double
is digits implementation-defined;
-- Characters and Strings
type char
is <implementation-defined character type>;
function To_C (Item :
in Character)
return char;
function To_Ada (Item :
in char)
return Character;
type char_array
is array (size_t
range <>)
of aliased char;
pragma Pack(char_array);
for char_array'Component_Size
use CHAR_BIT;
function Is_Nul_Terminated (Item :
in char_array)
return Boolean;
function To_C (Item :
in String;
Append_Nul :
in Boolean := True)
return char_array;
function To_Ada (Item :
in char_array;
Trim_Nul :
in Boolean := True)
return String;
procedure To_C (Item :
in String;
Target :
out char_array;
Count :
out size_t;
Append_Nul :
in Boolean := True);
procedure To_Ada (Item :
in char_array;
Target :
out String;
Count :
out Natural;
Trim_Nul :
in Boolean := True);
-- Wide Character and Wide String
function To_C (Item :
in Wide_Character)
return wchar_t;
function To_Ada (Item :
in wchar_t )
return Wide_Character;
type wchar_array
is array (size_t
range <>)
of aliased wchar_t;
pragma Pack(wchar_array);
function Is_Nul_Terminated (Item :
in wchar_array)
return Boolean;
function To_C (Item :
in Wide_String;
Append_Nul :
in Boolean := True)
return wchar_array;
function To_Ada (Item :
in wchar_array;
Trim_Nul :
in Boolean := True)
return Wide_String;
procedure To_C (Item :
in Wide_String;
Target :
out wchar_array;
Count :
out size_t;
Append_Nul :
in Boolean := True);
procedure To_Ada (Item :
in wchar_array;
Target :
out Wide_String;
Count :
out Natural;
Trim_Nul :
in Boolean := True);
{
AI95-00285-01}
--
ISO/IEC 10646:2003 compatible types defined by ISO/IEC TR 19769:2004.
{
AI95-00285-01}
type char16_t
is <implementation-defined character type>;
char16_nul :
constant char16_t :=
implementation-defined;
function To_C (Item :
in Wide_Character)
return char16_t;
function To_Ada (Item :
in char16_t)
return Wide_Character;
type char16_array
is array (size_t
range <>)
of aliased char16_t;
pragma Pack(char16_array);
function Is_Nul_Terminated (Item :
in char16_array)
return Boolean;
function To_C (Item :
in Wide_String;
Append_Nul :
in Boolean := True)
return char16_array;
function To_Ada (Item :
in char16_array;
Trim_Nul :
in Boolean := True)
return Wide_String;
procedure To_C (Item :
in Wide_String;
Target :
out char16_array;
Count :
out size_t;
Append_Nul :
in Boolean := True);
procedure To_Ada (Item :
in char16_array;
Target :
out Wide_String;
Count :
out Natural;
Trim_Nul :
in Boolean := True);
{
AI95-00285-01}
type char32_t
is <implementation-defined character type>;
char32_nul :
constant char32_t :=
implementation-defined;
function To_C (Item :
in Wide_Wide_Character)
return char32_t;
function To_Ada (Item :
in char32_t)
return Wide_Wide_Character;
type char32_array
is array (size_t
range <>)
of aliased char32_t;
pragma Pack(char32_array);
function Is_Nul_Terminated (Item :
in char32_array)
return Boolean;
function To_C (Item :
in Wide_Wide_String;
Append_Nul :
in Boolean := True)
return char32_array;
function To_Ada (Item :
in char32_array;
Trim_Nul :
in Boolean := True)
return Wide_Wide_String;
procedure To_C (Item :
in Wide_Wide_String;
Target :
out char32_array;
Count :
out size_t;
Append_Nul :
in Boolean := True);
procedure To_Ada (Item :
in char32_array;
Target :
out Wide_Wide_String;
Count :
out Natural;
Trim_Nul :
in Boolean := True);
Terminator_Error :
exception;
end Interfaces.C;
Implementation defined: The definitions
of certain types and constants in Interfaces.C.
Each of the types declared in Interfaces.C is C-compatible.
{
AI95-00285-01}
The types int, short, long, unsigned, ptrdiff_t, size_t, double, char,
wchar_t, char16_t, and char32_t correspond respectively to the C types
having the same names. The types signed_char, unsigned_short, unsigned_long,
unsigned_char, C_float, and long_double correspond respectively to the
C types signed char, unsigned short, unsigned long, unsigned char, float,
and long double.
Discussion: The C types wchar_t and char16_t
seem to be the same. However, wchar_t has an implementation-defined size,
whereas char16_t is guaranteed to be an unsigned type of at least 16
bits. Also, char16_t and char32_t are encouraged to have UTF-16 and UTF-32
representations; that means that they are not directly the same as the
Ada types, which most likely don't use any UTF encoding.
The type of the subtype
plain_char is either signed_char or unsigned_char, depending on the C
implementation.
function To_C (Item : in Character) return char;
function To_Ada (Item : in char ) return Character;
The functions To_C
and To_Ada map between the Ada type Character and the C type char.
Implementation Note: {
8652/0114}
{
AI95-00038-01}
The To_C and To_Ada functions map between corresponding characters, not
necessarily between characters with the same internal representation.
Corresponding characters are characters defined by the same enumeration
literal, if such exist; otherwise, the correspondence is unspecified.{
Unspecified
[partial]}
The following
definition is equivalent to the above summary:
To_C (Latin_1_Char) = char'Value(Character'Image(Latin_1_Char))
provided that char'Value does not raise an exception; otherwise the result
is unspecified.
To_Ada (Native_C_Char) = Character'Value(char'Image(Native_C_Char))
provided that Character'Value does not raise an exception; otherwise
the result is unspecified.
function Is_Nul_Terminated (Item : in char_array) return Boolean;
The result of Is_Nul_Terminated
is True if Item contains nul, and is False otherwise.
function To_C (Item : in String; Append_Nul : in Boolean := True)
return char_array;
function To_Ada (Item : in char_array; Trim_Nul : in Boolean := True)
return String;
{
AI95-00258-01}
The result of To_C is a char_array value of length Item'Length (if Append_Nul
is False) or Item'Length+1 (if Append_Nul is True). The lower bound is
0. For each component Item(I), the corresponding component in the result
is To_C applied to Item(I). The value nul is appended if Append_Nul is
True. If Append_Nul is False and Item'Length is 0, then To_C propagates
Constraint_Error.
The result of To_Ada
is a String whose length is Item'Length (if Trim_Nul is False) or the
length of the slice of Item preceding the first nul (if Trim_Nul is True).
The lower bound of the result is 1. If Trim_Nul is False, then for each
component Item(I) the corresponding component in the result is To_Ada
applied to Item(I). If Trim_Nul is True, then for each component Item(I)
before the first nul the corresponding component in the result is To_Ada
applied to Item(I). The function propagates Terminator_Error if Trim_Nul
is True and Item does not contain nul.
procedure To_C (Item : in String;
Target : out char_array;
Count : out size_t;
Append_Nul : in Boolean := True);
procedure To_Ada (Item : in char_array;
Target : out String;
Count : out Natural;
Trim_Nul : in Boolean := True);
For procedure To_C, each element of Item is converted
(via the To_C function) to a char, which is assigned to the corresponding
element of Target. If Append_Nul is True, nul is then assigned to the
next element of Target. In either case, Count is set to the number of
Target elements assigned.
{Constraint_Error
(raised by failure of run-time check)} If
Target is not long enough, Constraint_Error is propagated.
For procedure To_Ada,
each element of Item (if Trim_Nul is False) or each element of Item preceding
the first nul (if Trim_Nul is True) is converted (via the To_Ada function)
to a Character, which is assigned to the corresponding element of Target.
Count is set to the number of Target elements assigned.
{Constraint_Error
(raised by failure of run-time check)} If
Target is not long enough, Constraint_Error is propagated. If Trim_Nul
is True and Item does not contain nul, then Terminator_Error is propagated.
function Is_Nul_Terminated (Item : in wchar_array) return Boolean;
The result of Is_Nul_Terminated
is True if Item contains wide_nul, and is False otherwise.
function To_C (Item : in Wide_Character) return wchar_t;
function To_Ada (Item : in wchar_t ) return Wide_Character;
To_C and To_Ada
provide the mappings between the Ada and C wide character types.
function To_C (Item : in Wide_String;
Append_Nul : in Boolean := True)
return wchar_array;
function To_Ada (Item : in wchar_array;
Trim_Nul : in Boolean := True)
return Wide_String;
procedure To_C (Item : in Wide_String;
Target : out wchar_array;
Count : out size_t;
Append_Nul : in Boolean := True);
procedure To_Ada (Item : in wchar_array;
Target : out Wide_String;
Count : out Natural;
Trim_Nul : in Boolean := True);
The To_C and To_Ada subprograms that convert between
Wide_String and wchar_array have analogous effects to the To_C and To_Ada
subprograms that convert between String and char_array, except that wide_nul
is used instead of nul.
function Is_Nul_Terminated (Item : in char16_array) return Boolean;
{
AI95-00285-01}
The result of Is_Nul_Terminated is True if Item contains char16_nul,
and is False otherwise.
function To_C (Item : in Wide_Character) return char16_t;
function To_Ada (Item : in char16_t ) return Wide_Character;
{
AI95-00285-01}
To_C and To_Ada provide mappings between the Ada and C 16-bit character
types.
function To_C (Item : in Wide_String;
Append_Nul : in Boolean := True)
return char16_array;
function To_Ada (Item : in char16_array;
Trim_Nul : in Boolean := True)
return Wide_String;
procedure To_C (Item : in Wide_String;
Target : out char16_array;
Count : out size_t;
Append_Nul : in Boolean := True);
procedure To_Ada (Item : in char16_array;
Target : out Wide_String;
Count : out Natural;
Trim_Nul : in Boolean := True);
{
AI95-00285-01}
The To_C and To_Ada subprograms that convert between Wide_String and
char16_array have analogous effects to the To_C and To_Ada subprograms
that convert between String and char_array, except that char16_nul is
used instead of nul.
function Is_Nul_Terminated (Item : in char32_array) return Boolean;
{
AI95-00285-01}
The result of Is_Nul_Terminated is True if Item contains char16_nul,
and is False otherwise.
function To_C (Item : in Wide_Wide_Character) return char32_t;
function To_Ada (Item : in char32_t ) return Wide_Wide_Character;
{
AI95-00285-01}
To_C and To_Ada provide mappings between the Ada and C 32-bit character
types.
function To_C (Item : in Wide_Wide_String;
Append_Nul : in Boolean := True)
return char32_array;
function To_Ada (Item : in char32_array;
Trim_Nul : in Boolean := True)
return Wide_Wide_String;
procedure To_C (Item : in Wide_Wide_String;
Target : out char32_array;
Count : out size_t;
Append_Nul : in Boolean := True);
procedure To_Ada (Item : in char32_array;
Target : out Wide_Wide_String;
Count : out Natural;
Trim_Nul : in Boolean := True);
{
AI95-00285-01}
The To_C and To_Ada subprograms that convert between Wide_Wide_String
and char32_array have analogous effects to the To_C and To_Ada subprograms
that convert between String and char_array, except that char32_nul is
used instead of nul.
Discussion: The Interfaces.C package
provides an implementation-defined character type, char, designed to
model the C run-time character set, and mappings between the types char
and Character.
One application
of the C interface package is to compose a C string and pass it to a
C function. One way to do this is for the programmer to declare an object
that will hold the C array, and then pass this array to the C function.
This is realized via the type char_array:
type char_array is array (size_t range <>) of Char;
The programmer can declare an Ada String, convert
it to a char_array, and pass the char_array as actual parameter to the
C function that is expecting a char *.
An alternative approach is for the programmer
to obtain a C char pointer from an Ada String (or from a char_array)
by invoking an allocation function. The package Interfaces.C.Strings
(see below) supplies the needed facilities, including a private type
chars_ptr that corresponds to C's char *, and two allocation functions.
To avoid storage leakage, a Free procedure releases the storage that
was allocated by one of these allocate functions.
It is typical for a C function that deals with
strings to adopt the convention that the string is delimited by a nul
char. The C interface packages support this convention. A constant nul
of type Char is declared, and the function Value(Chars_Ptr) in Interfaces.C.Strings
returns a char_array up to and including the first nul in the array that
the chars_ptr points to. The Allocate_Chars function allocates an array
that is nul terminated.
Some C functions that deal with strings take
an explicit length as a parameter, thus allowing strings to be passed
that contain nul as a data element. Other C functions take an explicit
length that is an upper bound: the prefix of the string up to the char
before nul, or the prefix of the given length, is used by the function,
whichever is shorter. The C Interface packages support calling such functions.
{
8652/0059}
{
AI95-00131-01}
{
AI95-00216-01}
The eligibility rules in
B.1 do not apply to
convention C_Pass_By_Copy. Instead, a type T is eligible for convention
C_Pass_By_Copy if T is an unchecked union type or if T is a record type
that has no discriminants and that only has components with statically
constrained subtypes, and each component is C-compatible.
Implementation Requirements
{
8652/0059}
{
AI95-00131-01}
An implementation shall support pragma Convention with a C
convention_
identifier
for a C-eligible type (see
B.1). An implementation
shall support pragma Convention with a C_Pass_By_Copy
convention_
identifier
for a C_Pass_By_Copy-eligible type.
Implementation Permissions
An implementation may provide additional declarations
in the C interface packages.
Implementation Advice
Implementation Advice: The constants
nul, wide_nul, char16_nul, and char32_nul in package Interfaces.C should
have a representation of zero.
An implementation should support the following interface
correspondences between Ada and C.
An Ada procedure corresponds to a void-returning
C function.
Discussion: The programmer can also choose
an Ada procedure when the C function returns an int that is to be discarded.
An Ada function corresponds to a non-void C function.
An Ada in scalar parameter is passed as
a scalar argument to a C function.
An Ada in parameter of an access-to-object
type with designated type T is passed as a t* argument to a C function,
where t is the C type corresponding to the Ada type T.
An Ada access T parameter, or an Ada out
or in out parameter of an elementary type T, is passed as a t*
argument to a C function, where t is the C type corresponding to the
Ada type T. In the case of an elementary out or in out
parameter, a pointer to a temporary copy is used to preserve by-copy
semantics.
{
8652/0059}
{
AI95-00131-01}
{
AI95-00343-01}
An Ada parameter of a (record) type T of convention C_Pass_By_Copy, of
mode
in, is passed as a t argument to a C function, where t is
the C struct corresponding to the Ada type T.
{
8652/0059}
{
AI95-00131-01}
{
AI95-00343-01}
An Ada parameter of a record type T, of any mode, other than an
in
parameter of a type of convention C_Pass_By_Copy, is passed as a t* argument
to a C function, where t is the C struct corresponding to the Ada type
T.
An Ada parameter of an array type with component
type T, of any mode, is passed as a t* argument to a C function, where
t is the C type corresponding to the Ada type T.
An Ada parameter of an access-to-subprogram type
is passed as a pointer to a C function whose prototype corresponds to
the designated subprogram's specification.
{
AI95-00337-01}
An Ada parameter of a private type is passed as specified for the full
view of the type.
Implementation Advice: If C interfacing
is supported, the interface correspondences between Ada and C should
be supported.
8 Values of type char_array are not implicitly
terminated with nul. If a char_array is to be passed as a parameter to
an imported C function requiring nul termination, it is the programmer's
responsibility to obtain this effect.
9 To obtain the effect of C's sizeof(item_type),
where Item_Type is the corresponding Ada type, evaluate the expression:
size_t(Item_Type'Size/CHAR_BIT).
10 A C function that takes a variable number
of arguments can correspond to several Ada subprograms, taking various
specific numbers and types of parameters.
Examples
Example of using
the Interfaces.C package:
--Calling the C Library Function strcpy
with Interfaces.C;
procedure Test is
package C renames Interfaces.C;
use type C.char_array;
-- Call <string.h>strcpy:
-- C definition of strcpy: char *strcpy(char *s1, const char *s2);
-- This function copies the string pointed to by s2 (including the terminating null character)
-- into the array pointed to by s1. If copying takes place between objects that overlap,
-- the behavior is undefined. The strcpy function returns the value of s1.
-- Note: since the C function's return value is of no interest, the Ada interface is a procedure
procedure Strcpy (Target : out C.char_array;
Source : in C.char_array);
pragma Import(C, Strcpy, "strcpy");
Chars1 : C.char_array(1..20);
Chars2 : C.char_array(1..20);
begin
Chars2(1..6) := "qwert" & C.nul;
Strcpy(Chars1, Chars2);
-- Now Chars1(1..6) = "qwert" & C.Nul
end Test;
Incompatibilities With Ada 95
{
AI95-00285-01}
{
incompatibilities with Ada 95}
Types char16_t
and char32_t and their related types and operations are newly added to
Interfaces.C. If Interfaces.C is referenced in a
use_clause,
and an entity
E with the same
defining_identifier
as a new entity in Interfaces.C is defined in a package that is also
referenced in a
use_clause,
the entity
E may no longer be use-visible, resulting in errors.
This should be rare and is easily fixed if it does occur.
Extensions to Ada 95
Wording Changes from Ada 95
{
AI95-00216-01}
Specified that an unchecked union type (see
B.3.3)
is eligible for convention C_Pass_By_Copy.
{
AI95-00258-01}
Specified what happens if the To_C function tries to return a null string.
{
AI95-00337-01}
Clarified that the interface correspondences also apply to private types
whose full types have the specified characteristics.
{
AI95-00343-01}
Clarified that a type must have convention C_Pass_By_Copy in order to
be passed by copy (not just a type that could have that convention).
{
AI95-00376-01}
Added wording to make it clear that these facilities can also be used
with C++.