gauche.native-type - ネイティブタイプユーティリティ ¶このモジュールは、「ネイティブ」つまり「よりメタルに近い」層とやりとりする ためのインフラを提供します。例えばFFIやバイナリデータ構造体へのアクセス に必要な基礎部分です。
基本的なネイティブタイプは組み込みになっています(ネイティブタイプ参照)。 このモジュールはそれに加え、導出型や集合型(配列や構造体)、 バイトオーダーを特定した型、 ネイテイブタイプオブジェクトとその簡潔な表記(シグネチャ)の相互変換などを提供します。
また、ネイティブデータをSchemeからアクセスするための ネイティブハンドルも提供されます(ネイティブハンドル参照)。
| • 導出および集合ネイティブタイプ: | ||
| • レイアウトを特定した型: | ||
| • ネイティブタイプシグネチャ: | ||
| • ネイティブハンドル: |
We have subclasses of <native-type>, which are classes
of individual derived or aggregate native types.
For example, “pointer to int” native type is an instance of
<c-pointer> class. Note that <c-pointer> itself
is not an instance of <native-type>.
In C, tags of struct, union, and enum share the same namespace, and you cannot use the same tag to define different struct/union/enums.
We don’t automatically track tags by default. It’s up to the user to set up the tag namespace as required by the application. We have tools to help it.
{gauche.native-type}
A parameter that holds the current tag namespace. Its value must
be #f or an object created by
make-native-tag-namespace below.
If it is #f (default), tags are not tracked.
If it is a tag namespace object, whenever a new c-struct/c-union/c-enum
type is created, its tag is registered. If there’s already
a native type with the same tag, an error is signaled
unless the type definition exactly matches.
{gauche.native-type}
Create a new native tag namespace object (which is actually
an instance of <stacked-map>,
see 汎用ディクショナリ).
If parent is given and not #f, it must be another
tag namespace object. The new namespace is stacked on it—that is,
all the tags registered in parent is visible, but newly
added tags are put in the new namespace and do not affect parent.
{gauche.native-type}
Returns a c-struct/c-union/c-enum type associated with the tag
(symbol) int the namespace. If namespace is omitted
or #f, the value of current-native-tag-namespace
parameter is used.
{gauche.native-type}
A class of native types representing pointers. Can be created
with make-c-pointer-type, or from a signature
with native-type (e.g. (native-type 'int*),
see ネイティブタイプシグネチャ).
Note: At the moment, we don’t keep track of quoalifiers
such as const or volatile, but their support may
be added in future.
A native handle with a C pointer type can be “dereferenced”
with native* (see ネイティブハンドル).
{gauche.native-type}
The argument must be an native type instance.
Returns an native type represents a pointer to the pointee-type.
(make-c-pointer-type <int>) ⇒ #<c-pointer <int*>> (make-c-pointer-type (make-c-pointer-type <int>)) ⇒ #<c-pointer <int**>>
{gauche.native-type}
Returns the pointee type of the given c-pointer type.
(c-pointer-type-pointee (make-c-pointer-type <int>)) ⇒ #<native-type <int>>
{gauche.native-type}
A class of native types representing C-style arrays. Can be created
with make-c-array-type, or from a signature
with native-type (e.g. (native-type '(.array int (10))),
see ネイティブタイプシグネチャ).
Arrays can have more than one dimensions. Elements
with consectuve last indexes are laid adjacent on memory.
The length of the first dimension can be left unspecified
(we use * as a placeholder), just like C array
such as int a[][10][3].
An element, or a subarray, of an array represented by a
native handle with a C array type
can be accessed with native-aref (see ネイティブハンドル).
{gauche.native-type}
Creates a C array type, whose elements are of type element-type,
which must be a native type.
The dimensions argument must be a list of non-negative
exact integers, except that the first element may be a symbol *.
They specify the lengths of each dimension of the array. Each index
of dimensions starts with 0. * in the first dimension indicates
the length is unspecified.
{gauche.native-type}
Returns a list of lengths of dimensions of c-array-type.
{gauche.native-type}
A class of native types representing C function types. Can be created
with make-c-function-type, or from a signature
with native-type (e.g.
(native-type '(.function (int int) ::int)),
see ネイティブタイプシグネチャ).
Instances of <c-function> describe the signature of a C function:
its return type, argument types, and whether it accepts variable arguments.
A native handle with a <c-function> type can be cast to and from
a pointer-to-function type with cast-handle
(see ネイティブハンドル).
{gauche.native-type}
Returns a native type representing a C function that returns
return-type and takes arguments of the types listed in
argument-type-list. Both return-type and each element
of argument-type-list must be native type instances, with
an exception below.
The last element of argument-type-list can be the symbol ...,
and then the resulting type represents a variadic function (like C’s ...
in int printf(const char*, …)). The ... marker is
not a native type and is not included in the result of
c-function-type-argument-types.
(make-c-function-type <int> `(,<int> ,<double>)) ⇒ #<c-function int double -> int> (make-c-function-type <int> `(,<int> ...)) ⇒ #<c-function int ... -> int> (c-function-type-argument-types (make-c-function-type <int> `(,<int> ...))) ⇒ (#<native-type <int>>) (c-function-type-variadic? (make-c-function-type <int> `(,<int> ...))) ⇒ #t
{gauche.native-type}
Returns the return type of c-function-type as a native type instance.
{gauche.native-type}
Returns the list of argument types of c-function-type. Each element
is a native type instance. The variadic marker ... is not included;
use c-function-type-variadic? to check for variadic functions.
{gauche.native-type}
Returns #t if c-function-type represents a variadic function
(i.e., it was created with ... as the last element of the
argument-type list), #f otherwise.
{gauche.native-type}
A class of native types representing C struct and union types, respectively.
Can be created with make-c-struct-type and
make-c-union-type, or from a signature with
native-type (e.g.
(native-type '(.struct t (a::int b::char))),
see ネイティブタイプシグネチャ).
{gauche.native-type}
Returns a native type representing a C struct type or a C union type.
tag can be a symbol representing the struct/union tag, or #f
for untagged struct/union.
fields is a list of (symbol type), where
symbol names the field’s name, and type for its type.
type must be an instance of a native type.
When a struct/union type is constructed, its total size and each field’s offset are computed (in unions, all the offsets are 0).
{gauche.native-type}
Returns the tag (symbol) of c-struct/union-type.
If the type is untagged, #f is returned.
{gauche.native-type}
Returns a list of field names (symbols) of c-struct/union-type.
{gauche.native-type}
Returns the type and the byte offset of field-name (symbol)
of c-struct/union-type.
{gauche.native-type}
A class of native types representing C enum types.
C enum type is a subtype of <integer>.
A new enum type can be creatd with make-c-enum-type, or
from a signature with
native-type (e.g.
(native-type '(.enum Color (Red Green Blue))).
{gauche.native-type}
Returns the enum tag of a c-enum type type. If the type doesn’t
have a tag, #f is returned.
{gauche.native-type}
Returns a list of (enum-symbol . integer-value)
of a c-enum type type.
{gauche.native-type}
Returns the integer value corresponding to symbol
defined in a c-enum type type.
It is an error if symbol does not correspond to an enumerator introduced by type.
Note that, in C, the enumerator has the same scope as the
enum itself, but in gauche.native-type we don’t
track each enumerator in the outer scope yet,
so we need the c-enum type that introduced
the enumerator symbol to know the value.
{gauche.native-type}
Returns the enumerator symbol introduced by a c-enum type
that has the integer value. If there are more than
one enumerator symbol with value, the first one is
returned.
It is an error if type does not have an enumerator with value.
{gauche.native-type}
Returns #t if obj is an instance of <c-pointer>,
<c-array>, c-function>, c-struct, <c-union>,
or c-enum,
and #f otherwise, respectively.
{gauche.native-type}
Returns #t if obj is either a C pointer type,
a C array type, or a C function type. Handles of those types
can be “casted” to a pointer type, following the C semantics.
See cast-handle for the details (see ネイティブハンドル).
{gauche.native-type}
Returns #t if obj is either a C array type,
a C struct type, or a C union type.
{gauche.native-type}
Returns #t if obj is either
a C struct type, or a C union type.
Primitive native types such as <int16> read/write memory
with the system’s native endianness. For FFI it is fine. However,
if you read/write binary data for exchanging between systems,
you need to explicitly specify the endianness.
We have native types for that purpose.
{gauche.native-type}
These native types accesses binary data as the specified numeric type,
and the specified endianncess (-be for big-endian,
-le for little endian).
The endianness is only considered when reading from or writing to memory
through native handles (with native* etc, see ネイティブハンドル).
In other words, these types only makes sense when they are used
within derived or aggregate types.
A native type signature is a compact S-expression description of
a native type. It lets you specify pointer, array, struct, union, and
function types without explicitly calling the corresponding constructors
such as make-c-pointer-type.
The procedure native-type can parse a signature
and returns the native type instance it denotes; native-type->signature
performs the inverse conversion. Signatures are also recognized in
some other places where a native type is expected—for example, in
struct/union field type declarations within .struct and
.union signature forms (so compound types can be written
without first naming each piece).
The signature format has been used in Gauche-C interface for long time (stubs and CiSE), though hasn’t been documented well. Because of its origin to transfer C type declarations to S-expression, it may feel C-centric.
A bare symbol whose name matches a built-in C type name denotes the
corresponding primitive native type. Recognized names follow the
C spelling, e.g. int, u_int, short, u_short,
long, u_long, char, int8_t, uint8_t,
int16_t, uint16_t, int32_t, uint32_t,
int64_t, uint64_t, size_t, ssize_t,
ptrdiff_t, off_t, intptr_t, uintptr_t,
float, double, and void. See ネイティブタイプ
for the corresponding type instances and what Scheme values they accept.
C’s char denotes the native type <c-char>, for
<char> is used for Gauche’s character type. <c-char>
is mapped to a Scheme character with unicode range U+0000 to U+00FF.
If the C routine uses char as a byte-sized numeric value,
use int8_t or uint8_t (depending on signedness) instead.
The pseudo-name c-string denotes the <c-string> type
(NUL-terminated C string). This special name is provided because
C type const char * may simply mean a pointer to byte-sized
numeric data, thus ambiguous.
The endian-specified types listed in レイアウトを特定した型
are also accepted, by their underscore-separated names: int16_le,
int16_be, uint16_le, uint16_be, and likewise for
the 32-bit and 64-bit integer types and for float and double.
A symbol whose name ends with one or more asterisks denotes a pointer
type; each trailing asterisk wraps the rest of the type in one
additional layer of <c-pointer>. Thus int* is equivalent
to (make-c-pointer-type <int>), char** is a pointer to a
pointer to <c-char>, and so on.
C-style multi-token forms are also accepted as a list of symbols.
The list is normalized by stripping any const tokens and
concatenating the rest into a single symbol. Therefore
(char *), (char const*), (const char*),
(int * *), and (int** *) are all valid. The form
(const type) is also accepted, with const
currently ignored.
(We do not yet track const or volatile qualifiers on the
resulting native type; they are silently dropped. Support may be added
in the future.)
(.array element-type (dim ...))
Denotes a C-style array. element-type is itself a native type
signature. Each dim is a non-negative exact integer, except
that the leftmost dim may be the symbol * to indicate an
unspecified leading dimension (as in C’s int a[][3][4]).
Multiple dimensions describe a multi-dimensional array, with elements
that share leading indices laid out adjacently in memory (the last
index varies fastest).
(.struct tag (field-spec ...)) (.struct (field-spec ...)) (.union tag (field-spec ...)) (.union (field-spec ...))
Denote a C struct or union type. tag, when given, is a symbol that names the struct/union tag; the second form of each pair (with no tag) denotes an anonymous struct/union.
Each field-spec has the form
name::type, using the typed-variable notation
common across Gauche. name is a symbol naming the field, and
type is itself a native type signature, so fields may be of
compound type as well. For the convenience, the delimiter ::
may be concatenated to name and/or type–
for example, a::int and a :: int are equivalent.
(.enum [tag] [: typespec] (enumerator ...))
Denote a C enum type. tag, when given, is a symbol that names the enum tag. typespec is a native type signature to resolve to an integral type, or a native integral type instance, to specify the size and alignment of the enum. If typespec isn’t given, the size and alignment of the enum type follows the compiler settings with which Gauche runtime is compiled.
enumerator is either a symbol, or (symbol integer-value).
(.function (arg-type ...) return-type)
Denotes a C function type. Each arg-type and return-type
is itself a native type signature. If the last arg-type is the
literal symbol ..., the resulting type is variadic
(corresponding to C’s trailing ...); the ... marker is
not itself a type, and is not included in the argument-type list
returned by c-function-type-argument-types. Use
c-function-type-variadic? to test for variadicity.
If the argument is already an instance of <native-type>,
native-type returns it unchanged. This makes it convenient for
higher-level routines to accept either a signature or a previously
constructed type instance.
Notably, you can emulate C’s typedef by assigning native type
to a variable, and inserting it in another type signature:
(define foo (.struct foo (a::int b::int))) (native-type `(.array ,foo (10))) ⇒ #<c-array struct foo(10)>
(native-type 'int) ⇒ #<native-type <int>> (native-type 'int*) ⇒ #<c-pointer <int*>> (native-type 'char**) ⇒ #<c-pointer <c-char**>> (native-type '(char const *)) ⇒ #<c-pointer <c-char*>> (native-type 'c-string) ⇒ #<native-type <c-string>> (native-type '(.array int (3 4))) ⇒ #<c-array <int>(3 4)> (native-type '(.array int (* 3))) ⇒ #<c-array <int>(* 3)> (native-type '(.struct point (x::double y::double))) ⇒ #<c-struct struct point> (native-type '(.union v (i::int f::float))) ⇒ #<c-union union v> (native-type '(.function (int int) double)) ⇒ #<c-function <int> <int> -> <double>> (native-type '(.function (char* ...) int)) ⇒ #<c-function <c-char*> ... -> <int>>
{gauche.native-type}
The argument must be an S-expression type signature or
a native type instance. If it is a type signature, a native
type instance denoted by the type signature is returned.
If the argument is already a native type instance, it is returned
as is.
See above for the specification of a native type signature.
{gauche.native-type}
Returns a native type signature that denotes the given native type.
A native handle is a handle through which you can access native data. Native handles may be returned from a foreign function call, or you can create one from a binary buffer. C pointers, arrays, structs, and unions to be passed to and from foreign functions are reprensed by native handles.
{gauche.native-type}
The class of native handle. A native handle is either a typed
reference of, or a typed pointer to a native object.
Its type can be retrieved with native-handle-type.
The pointed or referenced object is retrieved with
type-specific accessors below.
A native handle can be of c-pointer, c-array, c-function, c-struct or c-union types. If it’s other than c-pointer type, native handle holds a reference. The distinction of pointers and references is vague in the Scheme world, since all heap-allocated Scheme objects are treated indirectly. But there’s a distinction in the C/C++ world; the following example session shows it.
(define inner (native-type '(.struct (a::int b::int)))) (define outer (native-type `(.struct (ref::,inner ptr::(,inner *))))) (define handle (uvector->native-handle (make-u8vector (~ outer'size)) outer)) (set! (native. (native. handle 'ref) 'a) 1) ; handle.ref.a = 1 (set! (native. (native. handle 'ref) 'b) 2) ; handle.ref.b = 2 (set! (native. handle 'ptr) (native& handle 'ref)) ; handle.ptr = &handle.ref (define inner-ref (native. handle 'ref)) ; inner& inner_ref = handle.ref inner-ref ⇒ #<native-handle struct anonymous@0x77a1b10f51f0> (define inner-ptr (native. handle 'ptr)) ; inner* inner_ptr = handle.ptr inner-ptr ⇒ #<native-handle <struct anonymous*>@0x77a1b10f51f0> (native. inner-ref 'a) ⇒ 1 ; inner_ref.a (native-> inner-ptr 'a) ⇒ 1 ; inner_ptr->a (native. (native* inner-ptr) 'b) ⇒ 2 ; (*inner_ptr).b
{gauche.native-type}
Returns the native type of the handle.
{gauche.native-type}
Returns #t if obj is a native handle of c-pointer type,
#f otherwise.
{gauche.native-type}
Returns #t if obj is a native handle of c-function type,
#f otherwise.
{gauche.native-type}
Returns #t if obj is a native handle of c-array type,
#f otherwise.
{gauche.native-type}
Returns #t if obj is a native handle of c-struct
and c-union type, respectively,
#f otherwise.
{gauche.native-type}
Returns #t if obj is a native handle of c-array,
c-struct, or c-union type,
#f otherwise.
{gauche.native-type}
Returns #t if obj is a native handle of c-array,
c-pointer, or c-function type.
{gauche.native-type}
Pointer dereference. handle must be a c-pointer handle.
Returns the pointed value boxed as a Scheme object.
if the pointed value is an object of c-pointer or c-aggregate types,
a native handle representing that object is returned.
{gauche.native-type}
You can use a generic setter to modify the value in the pointed location.
val must be a value acceptable as the pointee type of
the pointer.
{gauche.native-type}
Array reference. handle must be a c-array handle or c-pointer
handle (Allowing c-pointer here reflects the C semantics).
index must be a nonnegative integer or a list of nonnagative integers. If the element type is a primitive type, the value is returned as a Scheme value. If the element type is a pointer type or an aggregate type, the value is wrapped as a native handle.
C’s multidimensional array is effectively nested one-dimensional arrays. If you give indexes less than the rank of the array, a handle to the subarray is returned.
If the handle points to an unbounded c-array or a c-pointer, no boundary check is done with index. It is caller’s responsibility to ensure index falls in a valid range.
{gauche.native-type}
handle must be a c-array or c-pointer handle, and
index must be a nonnegative integer or a list of nonnagative
integers.
Sets val to the array at the position specified by index.
If the handle points to an unbounded c-array or a c-pointer, no boundary check is done with index. It is caller’s responsibility to ensure index falls in a valid range.
{gauche.native-type}
Struct/union field reference. handle must be a native handle
of c-struct or c-union type, and slot must be a symbol
naming its slot. An error is thrown if the struct/union doesn’t
have the named slot.
{gauche.native-type}
Sets val to the field slot of c-struct or c-union handle.
{gauche.native-type}
Indirect struct/union field reference. handle must be
a native handle of c-pointer to a c-struct or c-union.
(native-> handle slot) is the same as
(native. (native* handle) slot), just like
s->a and (*s).a are the same in C.
{gauche.native-type}
Sets val to the field slot of c-struct or c-union
pointed by a c-pointer handle handle.
{gauche.native-type}
This takes the pointer to an element inside an aggregate data
referenced by handle. The handle must be a
native handle fo type c-array, c-struct, or c-union. An error
is signaled if other type of native handle is given.
If handle is a c-struct or c-union, selector must be a symbol naming its field. A c-poitner handle points to the field is returned.
If handle is a c-array, selector must be a fixnum, or a list of fixnums, as the index to the array. If the array is 1-dimensional, a fixnum or a list of signle fixnum is accepted. A c-pointer handle points to the element is returned.
(define ts (native-type '(.struct (a::int)))) (define hs (uvector->native-handle (make-u8vector (~ ts'size)) ts)) (native& hs 'a) ⇒ #<native-handle <int*>@0x726ffcc1a060> (define ta (native-type '(.array int (10)))) (define ha (uvector->native-handle (make-u8vector (~ ta'size)) ta)) (native& ha 3) ⇒ #<native-handle <int*>@0x726ffcccd42c>
{gauche.native-type}
Returns a new native handle that points to the same memory region
of handle, but with type.
Optionally, you can specify a byte offset with offset
from the handle.
You can cast a pointer to another pointer, an aggregate (struct, union, array) to another aggregate, an array to a pointer or a pointer to an array.
If handle knows the valid memory range it references, it checks if type falls within the region. However, if the handle is obtained from an external C function call, the valid memory region isn’t often explicit, and it’s up to you to treat it safely.
{gauche.native-type}
Both handle-a and handle-b must be pointer-like
handles. It compares the value of those pointer values,
and returns either -1 (if handle-a is smaller),
0 (if both are the same), or 1 (if handle-a is greater).
{gauche.native-type}
Both handle-a and handle-b must be pointer-like
handles. It compares the value of those pointer values,
{gauche.native-type}
Both handle-a and handle-b must be references
to aggregate type objects. Returns either -1, 0,
or 1, depending on whether handle-a is smaller,
the same, or handle-a is greater. The actual types
of two handles may differ.
First, the sizes are compared. If they differ, that’s the result.
If the sizes are the same, contents are compared bytewise.
This is the same as how bytevector-comparator compares
two bytevectors (see 用意されている比較器).
{gauche.native-type}
Copy the memory content of size bytes
pointed or reference by src-handle
to the memory pointed or reference by dst-handle.
If size argument is omitted or #f,
bytes of the size determined by the type of src-handle
are copied.
Optional offset allows to copy from non-zero offset.
If integer size is given, size bytes from
src-handle + offset are copied. If size is
#f, from src-handle + offset to the end
of the type size are copied.
{gauche.native-type}
This creates a native handle of native type type, using a uniform
vector uv as the backing storage. This is useful to prepare
binary data in Scheme world. type must be a pointer or
an aggregate native type.
uv can also be #f, in which case a u8vector of size
to contain object of type is allocated and used.
If offset is given, it specifies a byte offset from the beginning of uv for the resulting handle to point to. Using offset, you can extract a native handle in the middle of larger binary data. If it is omitted, 0 is assumed.
The size of uv in bytes minus offset must be greater than or equal to the size of type, or an error is thrown.
The returned native handle can be passed to a foreign function. Note that, however, if the foreign function retains the pointer, it may not be visible from Gauche’s GC. You have to make sure to retain reference to uv or the resulting native handle in the Scheme world as far as the pointer is retained in the foreign world.
You can use any type of uniform vector as uv, but other than
u8vector and s8vector, the machine’s native endianness
is exposed as the binary data.
(define ip (uvector->native-handle '#u8(#xff #xff #xff #xff)
(native-type 'int32_t*)))
ip ⇒ #<native-handle <int32*>@0x7d6fbf442ff0>
(native* ip) ⇒ -1
{gauche.native-type}
Returns a c-pointer handle representing NULL pointer.
The optional argument type must be a c-pointer type and
specifies the type of the resulting handle. When omitted,
<void*> native type is assumed.
(For FFI calls, you can pass <void*> pointer to wherever
a pointer is expected.)
{gauche.native-type}
Returns #t if obj is a native handle representing
NULL pointer (of any c-pointer type), #f otherwise.