0
# C Interoperability
1
2
Scala Native nativelib provides comprehensive C interoperability through type aliases, string conversions, arrays, structures, function pointers, and variadic arguments for seamless integration with C libraries.
3
4
## C Type System
5
6
### Primitive Type Aliases
7
8
Direct mapping between Scala and C primitive types:
9
10
```scala { .api }
11
// Signed integer types
12
type CChar = Byte
13
type CSignedChar = Byte
14
type CShort = Short
15
type CInt = Int
16
type CLong = Size // Platform dependent
17
type CLongInt = Size
18
type CLongLong = Long
19
20
// Unsigned integer types
21
type CUnsignedChar = UByte
22
type CUnsignedShort = UShort
23
type CUnsignedInt = UInt
24
type CUnsignedLong = USize // Platform dependent
25
type CUnsignedLongLong = ULong
26
27
// Floating point types
28
type CFloat = Float
29
type CDouble = Double
30
31
// Character types
32
type CWideChar = UInt // C++ wchar_t
33
type CChar16 = UShort // C++ char16_t
34
type CChar32 = UInt // C++ char32_t
35
36
// Boolean and size types
37
type CBool = Boolean // C _Bool, C++ bool
38
type CSize = USize // size_t
39
type CSSize = Size // ssize_t
40
type CPtrDiff = Size // ptrdiff_t
41
42
// Pointer types
43
type CVoidPtr = Ptr[Byte]
44
type CString = Ptr[CChar]
45
type CWideString = Ptr[CWideChar]
46
```
47
48
## String Conversions
49
50
### C String Functions
51
52
```scala { .api }
53
def fromCString(cstr: CString, charset: Charset = Charset.defaultCharset()): String
54
def toCString(str: String)(implicit z: Zone): CString
55
def toCString(str: String, charset: Charset)(implicit z: Zone): CString
56
```
57
58
**String conversion functions**:
59
- `fromCString(cstr, charset)` - Convert null-terminated C string to Scala String
60
- `toCString(str)` - Convert Scala String to C string using default charset
61
- `toCString(str, charset)` - Convert Scala String to C string with specified charset
62
63
### Wide String Functions
64
65
```scala { .api }
66
def fromCWideString(cwstr: CWideString, charset: Charset): String
67
def fromCWideString(cwstr: Ptr[CChar16], charset: Charset): String
68
def toCWideString(str: String, charset: Charset = StandardCharsets.UTF_16LE)(implicit z: Zone): CWideString
69
def toCWideStringUTF16LE(str: String)(implicit z: Zone): Ptr[CChar16]
70
```
71
72
**Wide string functions**:
73
- `fromCWideString` - Convert wide C string to Scala String
74
- `toCWideString` - Convert Scala String to wide C string
75
- `toCWideStringUTF16LE` - Convert to UTF-16 LE wide string
76
77
### String Literal Interpolation
78
79
```scala { .api }
80
implicit class CQuote(val ctx: StringContext) {
81
def c(): CString
82
}
83
```
84
85
**Usage**: `c"Hello World"` creates a compile-time C string literal.
86
87
## C Arrays
88
89
### CArray Type
90
91
Fixed-size C-style arrays with compile-time size information:
92
93
```scala { .api }
94
final class CArray[T, N <: Nat] {
95
def length(implicit tag: Tag[N]): Int
96
def apply(idx: Int)(implicit tag: Tag[T]): T
97
def update(idx: Int, value: T)(implicit tag: Tag[T]): Unit
98
def at(idx: Int)(implicit tag: Tag[T]): Ptr[T]
99
}
100
```
101
102
**CArray methods**:
103
- `length` - Get array length (compile-time constant)
104
- `apply(idx)` - Read element at index
105
- `update(idx, value)` - Write element at index
106
- `at(idx)` - Get pointer to element at index
107
108
### Natural Numbers for Array Sizes
109
110
```scala { .api }
111
sealed abstract class Nat
112
113
object Nat {
114
class _0 extends Nat
115
class _1 extends Nat
116
class _2 extends Nat
117
class _3 extends Nat
118
// ... continues to higher numbers
119
120
// Digit types for building larger numbers
121
class Digit2[N <: Nat] extends Nat
122
class Digit3[N <: Nat] extends Nat
123
// ... up to Digit9
124
}
125
```
126
127
## C Structures
128
129
### Structure Types
130
131
Type-safe C structure representations with field access:
132
133
```scala { .api }
134
sealed abstract class CStruct
135
136
final class CStruct0 {
137
def toPtr: Ptr[CStruct0]
138
}
139
140
final class CStruct1[T1] extends CStruct {
141
def toPtr: Ptr[CStruct1[T1]]
142
def at1(implicit tag: Tag.CStruct1[T1]): Ptr[T1]
143
def _1(implicit tag: Tag.CStruct1[T1]): T1
144
def _1_=(value: T1)(implicit tag: Tag.CStruct1[T1]): Unit
145
}
146
147
final class CStruct2[T1, T2] extends CStruct {
148
def toPtr: Ptr[CStruct2[T1, T2]]
149
def at1(implicit tag: Tag.CStruct2[T1, T2]): Ptr[T1]
150
def at2(implicit tag: Tag.CStruct2[T1, T2]): Ptr[T2]
151
def _1(implicit tag: Tag.CStruct2[T1, T2]): T1
152
def _1_=(value: T1)(implicit tag: Tag.CStruct2[T1, T2]): Unit
153
def _2(implicit tag: Tag.CStruct2[T1, T2]): T2
154
def _2_=(value: T2)(implicit tag: Tag.CStruct2[T1, T2]): Unit
155
}
156
157
// Complete family: CStruct3 through CStruct22 available
158
// Each CStructN provides _1 through _N field access and at1 through atN pointer access
159
160
final class CStruct3[T1, T2, T3] extends CStruct {
161
def toPtr: Ptr[CStruct3[T1, T2, T3]]
162
def at1: Ptr[T1]
163
def at2: Ptr[T2]
164
def at3: Ptr[T3]
165
def _1: T1
166
def _1_=(value: T1): Unit
167
def _2: T2
168
def _2_=(value: T2): Unit
169
def _3: T3
170
def _3_=(value: T3): Unit
171
}
172
173
// Pattern continues: CStruct4, CStruct5, ... CStruct22
174
// Maximum 22 fields supported (matches Scala function arity limit)
175
```
176
177
**Complete CStruct Family**:
178
- `CStruct0` - Empty structure (no fields)
179
- `CStruct1[T1]` through `CStruct22[T1, T2, ..., T22]` - Structures with 1-22 typed fields
180
- Field access: `struct._1`, `struct._2`, etc.
181
- Field assignment: `struct._1 = value`
182
- Pointer to field: `struct.at1`, `struct.at2`, etc.
183
- Pointer to struct: `struct.toPtr`
184
- All structures extend `CStruct` base trait
185
186
## Function Pointers
187
188
### Function Pointer Types
189
190
Type-safe function pointers for C callbacks and native function calls:
191
192
```scala { .api }
193
sealed abstract class CFuncPtr
194
195
// Base function pointer companion with conversion utilities
196
object CFuncPtr {
197
def fromPtr[F <: CFuncPtr](ptr: CVoidPtr): F
198
def toPtr(ptr: CFuncPtr): CVoidPtr
199
}
200
201
// Zero-argument function pointer
202
final class CFuncPtr0[R] extends CFuncPtr {
203
def apply(): R
204
}
205
206
object CFuncPtr0 {
207
implicit def fromScalaFunction[R](fn: Function0[R]): CFuncPtr0[R]
208
}
209
210
// Single-argument function pointer
211
final class CFuncPtr1[T1, R] extends CFuncPtr {
212
def apply(arg1: T1): R
213
}
214
215
object CFuncPtr1 {
216
implicit def fromScalaFunction[T1, R](fn: Function1[T1, R]): CFuncPtr1[T1, R]
217
}
218
219
// Two-argument function pointer
220
final class CFuncPtr2[T1, T2, R] extends CFuncPtr {
221
def apply(arg1: T1, arg2: T2): R
222
}
223
224
object CFuncPtr2 {
225
implicit def fromScalaFunction[T1, T2, R](fn: Function2[T1, T2, R]): CFuncPtr2[T1, T2, R]
226
}
227
228
// Three-argument function pointer
229
final class CFuncPtr3[T1, T2, T3, R] extends CFuncPtr {
230
def apply(arg1: T1, arg2: T2, arg3: T3): R
231
}
232
233
object CFuncPtr3 {
234
implicit def fromScalaFunction[T1, T2, T3, R](fn: Function3[T1, T2, T3, R]): CFuncPtr3[T1, T2, T3, R]
235
}
236
237
// Pattern continues: CFuncPtr4 through CFuncPtr22
238
// Each CFuncPtrN supports N arguments with type parameters T1, T2, ..., TN, R
239
// All provide apply(arg1, arg2, ..., argN): R method
240
// All companion objects provide implicit conversion from corresponding Scala FunctionN
241
```
242
243
**Complete CFuncPtr Family**:
244
- `CFuncPtr0[R]` through `CFuncPtr22[T1, T2, ..., T22, R]` - Function pointers with 0-22 arguments
245
- Type-safe function calls through `apply()` method
246
- Implicit conversions from Scala functions: `Function0` through `Function22`
247
- Zero-cost abstraction over native function pointers
248
- Pointer conversion utilities in `CFuncPtr` companion object
249
250
**Function pointer usage**:
251
- Direct calls: `funcPtr(arg1, arg2)`
252
- Conversion from Scala functions: `val cFuncPtr: CFuncPtr2[Int, Int, Int] = (a: Int, b: Int) => a + b`
253
- Pointer manipulation: `CFuncPtr.toPtr(funcPtr)` and `CFuncPtr.fromPtr[CFuncPtr1[Int, Int]](ptr)`
254
255
## Variadic Arguments
256
257
### CVarArg Types
258
259
Support for C-style variadic function calls:
260
261
```scala { .api }
262
abstract class CVarArg
263
264
final class CVarArgList {
265
// Internal implementation for variadic calls
266
}
267
268
def toCVarArgList()(implicit z: Zone): CVarArgList
269
def toCVarArgList(vararg: CVarArg, varargs: CVarArg*)(implicit z: Zone): CVarArgList
270
def toCVarArgList(varargs: Seq[CVarArg])(implicit z: Zone): CVarArgList
271
```
272
273
**Variadic argument functions**:
274
- `toCVarArgList()` - Create empty vararg list
275
- `toCVarArgList(args...)` - Create vararg list from arguments
276
- `toCVarArgList(seq)` - Create vararg list from sequence
277
278
## External Annotations
279
280
### Annotation Types
281
282
Annotations for marking external C interface elements:
283
284
```scala { .api }
285
final class extern extends scala.annotation.StaticAnnotation
286
final class blocking extends scala.annotation.StaticAnnotation
287
288
def extern: Nothing
289
```
290
291
**External annotations**:
292
- `@extern` - Mark objects containing external definitions
293
- `@blocking` - Mark methods that may block (for threading)
294
- `extern` - Right-hand side value for external declarations
295
296
## Usage Examples
297
298
### Basic C String Usage
299
300
```scala
301
import scala.scalanative.unsafe._
302
import java.nio.charset.StandardCharsets
303
304
Zone.acquire { implicit z =>
305
// Convert Scala string to C string
306
val message = "Hello from Scala Native!"
307
val cstring: CString = toCString(message)
308
309
// Use with C function (hypothetical)
310
// puts(cstring)
311
312
// Convert back to Scala string
313
val recovered: String = fromCString(cstring)
314
315
// With specific charset
316
val utf8String: CString = toCString(message, StandardCharsets.UTF_8)
317
}
318
```
319
320
### C Array Usage
321
322
```scala
323
import scala.scalanative.unsafe._
324
325
// Define array size at type level
326
type Array10 = CArray[CInt, Nat.Digit1[Nat._0]] // Size 10
327
328
Zone.acquire { implicit z =>
329
val array = alloc[Array10]
330
331
// Access like normal array
332
array(0) = 42
333
array(1) = 84
334
335
val length = array.length // Compile-time constant: 10
336
val value = array(0) // Read: 42
337
338
// Get pointer to element
339
val ptr = array.at(5)
340
!ptr = 123
341
}
342
```
343
344
### C Structure Usage
345
346
```scala
347
import scala.scalanative.unsafe._
348
349
// Define a point structure
350
type Point = CStruct2[CDouble, CDouble]
351
352
Zone.acquire { implicit z =>
353
val point = alloc[Point]
354
355
// Set coordinates
356
point._1 = 3.14 // x coordinate
357
point._2 = 2.71 // y coordinate
358
359
// Read coordinates
360
val x: CDouble = point._1
361
val y: CDouble = point._2
362
363
// Get pointers to fields
364
val xPtr = point.at1
365
val yPtr = point.at2
366
}
367
```
368
369
### Function Pointer Usage
370
371
```scala
372
import scala.scalanative.unsafe._
373
374
// C function signature: int compare(int a, int b)
375
type CompareFn = CFuncPtr2[CInt, CInt, CInt]
376
377
def useComparator(compareFn: CompareFn): CInt = {
378
// Call the function pointer
379
val result = compareFn(42, 24)
380
result
381
}
382
383
// Convert Scala function to function pointer
384
val scalaComparator: (CInt, CInt) => CInt = (a, b) => a - b
385
val cFuncPtr: CompareFn = scalaComparator
386
387
val result = useComparator(cFuncPtr)
388
```
389
390
### External Function Declaration
391
392
```scala
393
import scala.scalanative.unsafe._
394
395
@extern
396
object LibC {
397
// C function: int puts(const char* str)
398
def puts(str: CString): CInt = extern
399
400
// C function: void* malloc(size_t size)
401
def malloc(size: CSize): Ptr[Byte] = extern
402
403
// C function: void free(void* ptr)
404
def free(ptr: Ptr[Byte]): Unit = extern
405
406
// Blocking I/O function
407
@blocking
408
def read(fd: CInt, buf: Ptr[Byte], count: CSize): CSSize = extern
409
}
410
411
// Usage
412
Zone.acquire { implicit z =>
413
val message = toCString("Hello from C!")
414
LibC.puts(message)
415
}
416
```
417
418
## Best Practices
419
420
1. **Use Zone.acquire** for automatic memory management of converted strings
421
2. **Specify charsets explicitly** when working with non-ASCII text
422
3. **Check for null** when receiving C strings from external functions
423
4. **Use appropriate structure types** - match C struct layout exactly
424
5. **Convert function pointers carefully** - ensure calling conventions match
425
6. **Handle variadic arguments properly** - convert all arguments to CVarArg first
426
7. **Use @blocking annotation** for functions that may block to ensure proper threading behavior