Skip to content

C Interoperability

For the ABI responsibilities and exact declaration rules, see Attributes, Directives, and Interoperability.

DQ is designed to call C libraries directly. Interop code normally combines external declarations, C-compatible types, pointers, and #linklib.

External Functions

Declare C functions with [[external]].

func printf(fmt : ^char, ...) -> int  [[external]]

When the DQ name should differ from the C symbol, pass the symbol name.

func c_fprintf(stream : pointer, fmt : ^char, ...) -> int  [[external('fprintf')]]

Variable Arguments

C-style variadic functions use ....

[[external]] func printf(fmt : ^char, ...) -> int

printf("value = %d\n", 42)

Use C-compatible argument types and format strings that match the external ABI.

External Global Variables

External global variables can use the DQ declaration name or an explicit native symbol name.

var errno : int [[external]]
var libc_stdout : pointer [[external('stdout')]]

Embedded Strings

Use ^char, str.pchar, embstr, and embstr(n) for C-style strings.

func WriteStr(s : embstr):
    var p : ^char = s.pchar
    while p^ <> 0:
        putchar(p^)
        p += 1
    endwhile
endfunc

embstr(n) declares exactly n bytes of fixed storage, including its zero terminator; its maximum content length is n - 1.

var buf : embstr(127) = "hello"

str has an enforced trailing zero and can be passed with .pchar without copying. Internal zero bytes are still possible; a C API using zero-terminated semantics sees only the prefix before the first zero byte.

Generic Pointers

Use pointer for opaque C pointers.

[[external]] func fopen(path : ^char, mode : ^char) -> pointer
[[external]] func fclose(file : pointer) -> int

Cast to typed pointers before dereferencing.

Struct Layout

Use structs for C-compatible records when layout is known.

struct SPoint:
    x : int32
    y : int32
endstruct

Attributes such as [[packed]], [[align(n)]], and [[volatile]] are available for low-level layout/access cases where supported by the compiler. Memory-mapped register fields can use [[regrw]], [[regro]], and [[regwo]] for volatile read/write, read-only, and write-only access respectively.

Linking Libraries

Use #linklib to request an external library.

#linklib('z')
[[external]] func zlibVersion() -> ^char

Standard Package Declarations

The stdpkg/libc modules provide some existing C declarations.

use libc/stdio

ABI Responsibility

DQ type checking verifies the DQ side of the declaration, but the programmer is responsible for matching the real C ABI: integer widths, pointer types, struct layout, calling convention, variadic arguments, ownership, and lifetime.