Skip to content

Commit 6301e02

Browse files
authored
Merge pull request #29677 from benrimmington/how-swift-imports-c
2 parents 6de9f11 + d30ea11 commit 6301e02

File tree

1 file changed

+53
-70
lines changed

1 file changed

+53
-70
lines changed

docs/HowSwiftImportsCAPIs.md

Lines changed: 53 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# How Swift imports C APIs
22

3-
When Swift imports a module or parses a bridging header from a C-based language
3+
When Swift imports a module, or parses a bridging header from a C-based language
44
(C, Objective-C), the APIs are mapped into Swift APIs and can be used directly
55
from Swift code. This provides the basis for Swift's Foreign Function Interface
66
(FFI), providing interoperability with existing libraries written in C-based
7-
languages. This document describes how APIs from C-based languages are mapped
8-
into Swift APIs.
7+
languages.
98

10-
this document is written for a broad audience, including Swift and C users who
9+
This document describes how APIs from C-based languages are mapped into Swift
10+
APIs. It is written for a broad audience, including Swift and C users who
1111
might not be language experts. Therefore, it explains some advanced concepts
1212
where necessary.
1313

@@ -34,17 +34,17 @@ where necessary.
3434
* [Typedefs](#typedefs)
3535
* [Macros](#macros)
3636

37-
# Names, identifiers and keywords
37+
## Names, identifiers and keywords
3838

39-
## Unicode
39+
### Unicode
4040

4141
C (and C++) permit non-ASCII Unicode code points in identifiers. While Swift
4242
does not permit arbitrary Unicode code points in identifiers (so compatibility
4343
might not be perfect), it tries to allow reasonable ones. However, C,
4444
Objective-C, and C++ code in practice does not tend to use non-ASCII code points
4545
in identifiers, so mapping them to Swift is not an important concern.
4646

47-
## Names that are keywords in Swift
47+
### Names that are keywords in Swift
4848

4949
Some C and C++ identifiers are keywords in Swift. Despite that, such names are
5050
imported as-is into Swift, because Swift permits escaping keywords to use them
@@ -74,22 +74,22 @@ func test() {
7474
}
7575
```
7676

77-
## Name translation
77+
### Name translation
7878

7979
Names of some C declarations appear in Swift differently. In particular, names
8080
of enumerators (enum constants) go through a translation process that is
8181
hardcoded into the compiler. For more details, see [Name Translation from C to
8282
Swift](CToSwiftNameTranslation.md).
8383

84-
## Name customization
84+
### Name customization
8585

8686
As a general principle of Swift/C interoperability, the C API vendor has broad
8787
control over how their APIs appear in Swift. In particular, the vendor can use
8888
the `swift_name` Clang attribute to customize the names of their C APIs in order
8989
to be more idiomatic in Swift. For more details, see [Name Translation from C to
9090
Swift](CToSwiftNameTranslation.md).
9191

92-
# Size, stride, and alignment of types
92+
## Size, stride, and alignment of types
9393

9494
In C, every type has a size (computed with the `sizeof` operator), and an
9595
alignment (computed with `alignof`).
@@ -159,7 +159,7 @@ print(MemoryLayout<CStructWithPadding>.size) // 4
159159
print(MemoryLayout<CStructWithPadding>.stride) // 4
160160
```
161161

162-
# Fundamental types
162+
## Fundamental types
163163

164164
In C, certain types (`char`, `int`, `float` etc.) are built into the language
165165
and into the compiler. These builtin types have behaviors that are not possible
@@ -289,12 +289,12 @@ double Add(int x, long y);
289289
func Add(_ x: CInt, _ y: CLong) -> CDouble
290290
```
291291

292-
# Free functions
292+
## Free functions
293293

294294
C functions are imported as free functions in Swift. Each type in the signature
295295
of the C function is mapped to the corresponding Swift type.
296296

297-
## Argument labels
297+
### Argument labels
298298

299299
Imported C functions don't have argument labels in Swift by default. Argument
300300
labels can be added by API owners through annotations in the C header.
@@ -322,7 +322,7 @@ drawString("hello", 10, 20)
322322
drawStringRenamed("hello", x: 10, y: 20)
323323
```
324324

325-
## Variadic arguments
325+
### Variadic arguments
326326

327327
C functions with variadic arguments are not imported into Swift, however, there
328328
are no technical reasons why they can't be imported.
@@ -344,7 +344,7 @@ See also Apple's documentation about this topic: [Use a CVaListPointer to Call
344344
Variadic
345345
Functions](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_functions_in_swift#2992073).
346346

347-
## Inline functions
347+
### Inline functions
348348

349349
Inline C functions that are defined in headers are imported as regular Swift
350350
functions. However, unlike free functions, inline functions require the caller
@@ -356,7 +356,7 @@ the C inline function. LLVM IR for C inline functions and LLVM IR for Swift code
356356
is put into one LLVM module, allowing all LLVM optimizations (like inlining) to
357357
work transparently across language boundaries.
358358

359-
# Global variables
359+
## Global variables
360360

361361
Global C variables are imported as Swift variables or constants, depending on
362362
constness.
@@ -375,7 +375,7 @@ var NumAlpacas: CInt
375375
let NumLlamas: CInt
376376
```
377377

378-
# Pointers to data
378+
## Pointers to data
379379

380380
C has one way to form a pointer to a value of type `T` -- `T*`.
381381

@@ -420,7 +420,7 @@ void AddSecondToFirst(int *x, const long *y);
420420
func AddSecondToFirst(_ x: UnsafeMutablePointer<CInt>!, _ y: UnsafePointer<CLong>!)
421421
```
422422

423-
# Nullable and non-nullable pointers
423+
## Nullable and non-nullable pointers
424424

425425
Any C pointer can be null. However, in practice, many pointers are never null.
426426
Therefore, code often does not expect certain pointers to be null and does not
@@ -559,7 +559,7 @@ See also Apple's documentation about this topic: [Designating Nullability in
559559
Objective-C
560560
APIs](https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/designating_nullability_in_objective-c_apis).
561561

562-
# Incomplete types and pointers to them
562+
## Incomplete types and pointers to them
563563

564564
C and C++ have a notion of incomplete types; Swift does not have anything
565565
similar. Incomplete C types are not imported in Swift in any form.
@@ -589,7 +589,7 @@ void Print(const Foo* foo);
589589
func Print(_ foo: OpaquePointer)
590590
```
591591

592-
# Function pointers
592+
## Function pointers
593593

594594
C supports only one form of function pointers: `Result (*)(Arg1, Arg2, Arg3)`.
595595

@@ -641,23 +641,23 @@ void qsort_annotated(
641641
642642
func qsort(
643643
_ base: UnsafeMutableRawPointer!,
644-
_ nmemb: CInt,
645-
_ size: CInt,
644+
_ nmemb: Int,
645+
_ size: Int,
646646
_ compar: (@convention(c) (UnsafeRawPointer?, UnsafeRawPointer?) -> CInt)!
647647
)
648648
649649
func qsort_annotated(
650650
_ base: UnsafeMutableRawPointer,
651-
_ nmemb: CInt,
652-
_ size: CInt,
651+
_ nmemb: Int,
652+
_ size: Int,
653653
_ compar: @convention(c) (UnsafeRawPointer, UnsafeRawPointer) -> CInt
654654
)
655655
```
656656

657657
See also Apple's documentation about this topic: [Using Imported C Functions in
658658
Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_functions_in_swift)
659659

660-
# Fixed-size arrays
660+
## Fixed-size arrays
661661

662662
C's fixed-size arrays are imported as Swift tuples.
663663

@@ -685,7 +685,7 @@ Fixed-size arrays are a commonly requested feature in Swift, and a good proposal
685685
is likely to be accepted. Once Swift has fixed-size arrays natively in the
686686
language, we can use them to improve C interoperability.
687687

688-
# Structs
688+
## Structs
689689

690690
C structs are imported as Swift structs, their fields are mapped to stored Swift
691691
properties. Bitfields are mapped to computed Swift properties. Swift structs
@@ -752,17 +752,17 @@ struct StructWithAnonymousStructs {
752752
// C header imported in Swift.
753753
struct StructWithAnonymousStructs {
754754
struct __Unnamed_struct___Anonymous_field0 {
755-
var x: Int32
755+
var x: CInt
756756
init()
757-
init(x: Int32)
757+
init(x: CInt)
758758
}
759759
struct __Unnamed_struct_containerForY {
760-
var y: Int32
760+
var y: CInt
761761
init()
762-
init(y: Int32)
762+
init(y: CInt)
763763
}
764764
var __Anonymous_field0: StructWithAnonymousStructs.__Unnamed_struct___Anonymous_field0
765-
var x: Int32
765+
var x: CInt
766766
var containerForY: StructWithAnonymousStructs.__Unnamed_struct_containerForY
767767

768768
// Default initializer that sets all properties to zero.
@@ -780,7 +780,7 @@ See also Apple's documentation about this topic: [Using Imported C Structs and
780780
Unions in
781781
Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift).
782782

783-
# Unions
783+
## Unions
784784

785785
Swift does not have a direct equivalent to a C union. C unions are mapped to
786786
Swift structs with computed properties that read from/write to the same
@@ -811,7 +811,7 @@ See also Apple's documentation about this topic: [Using Imported C Structs and
811811
Unions in
812812
Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift).
813813

814-
# Enums
814+
## Enums
815815

816816
We would have liked to map C enums to Swift enums, like this:
817817

@@ -829,7 +829,7 @@ enum HomeworkExcuse {
829829
```swift
830830
// C header imported in Swift: aspiration, not an actual mapping!
831831

832-
enum HomeworkExcuse : UInt32 {
832+
enum HomeworkExcuse: CUnsignedInt {
833833
case EatenByPet
834834
case ForgotAtHome
835835
case ThoughtItWasDueNextWeek
@@ -841,11 +841,11 @@ However, in practice, plain C enums are mapped to Swift structs like this:
841841
```swift
842842
// C header imported in Swift: actual mapping.
843843

844-
struct HomeworkExcuse : Equatable, RawRepresentable {
845-
init(_ rawValue: UInt32)
846-
init(rawValue: UInt32)
847-
var rawValue: UInt32
848-
typealias RawValue = UInt32
844+
struct HomeworkExcuse: Equatable, RawRepresentable {
845+
init(_ rawValue: CUnsignedInt)
846+
init(rawValue: CUnsignedInt)
847+
var rawValue: CUnsignedInt { get }
848+
typealias RawValue = CUnsignedInt
849849
}
850850
var EatenByPet: HomeworkExcuse { get }
851851
var ForgotAtHome: HomeworkExcuse { get }
@@ -902,13 +902,6 @@ does not handle all cases available at the compilation time.
902902
```c
903903
// C header.
904904

905-
// Enum that is not explicitly marked as either open or closed.
906-
enum HomeworkExcuse {
907-
EatenByPet,
908-
ForgotAtHome,
909-
ThoughtItWasDueNextWeek,
910-
};
911-
912905
// An open enum: we expect to add more kinds of input devices in future.
913906
enum InputDevice {
914907
Keyboard,
@@ -929,30 +922,20 @@ enum CardinalDirection {
929922
```swift
930923
// C header imported in Swift.
931924

932-
struct HomeworkExcuse : Equatable, RawRepresentable {
933-
init(_ rawValue: UInt32)
934-
init(rawValue: UInt32)
935-
var rawValue: UInt32
936-
typealias RawValue = UInt32
937-
}
938-
var EatenByPet: HomeworkExcuse { get }
939-
var ForgotAtHome: HomeworkExcuse { get }
940-
var ThoughtItWasDueNextWeek: HomeworkExcuse { get }
941-
942-
enum InputDevice : UInt32 {
943-
init?(rawValue: UInt32)
944-
var rawValue: UInt32 { get }
945-
typealias RawValue = UInt32
925+
enum InputDevice: CUnsignedInt, Hashable, RawRepresentable {
926+
init?(rawValue: CUnsignedInt)
927+
var rawValue: CUnsignedInt { get }
928+
typealias RawValue = CUnsignedInt
946929
case Keyboard
947930
case Mouse
948931
case Touchscreen
949932
}
950933

951-
@_frozen
952-
enum CardinalDirection : UInt32 {
953-
init?(rawValue: UInt32)
954-
var rawValue: UInt32 { get }
955-
typealias RawValue = UInt32
934+
@frozen
935+
enum CardinalDirection: CUnsignedInt, Hashable, RawRepresentable {
936+
init?(rawValue: CUnsignedInt)
937+
var rawValue: CUnsignedInt { get }
938+
typealias RawValue = CUnsignedInt
956939
case East
957940
case West
958941
case North
@@ -991,12 +974,12 @@ numeric and typed values.
991974
// Converting enum values to integers and back.
992975

993976
var south: CardinalDirection = .South
994-
// var southAsInteger: UInt32 = south // error: type mismatch
995-
var southAsInteger: UInt32 = south.rawValue // = 3
996-
var southAsEnum = CardinalDirection(rawValue: 3) // = South
977+
// var southAsInteger: CUnsignedInt = south // error: type mismatch
978+
var southAsInteger: CUnsignedInt = south.rawValue // = 3
979+
var southAsEnum = CardinalDirection(rawValue: 3) // = .South
997980
```
998981

999-
# Typedefs
982+
## Typedefs
1000983

1001984
C typedefs are generally mapped to Swift typealiases, except for a few common C
1002985
coding patterns that are handled in a special way.
@@ -1027,7 +1010,7 @@ struct Point {
10271010
}
10281011
```
10291012

1030-
# Macros
1013+
## Macros
10311014

10321015
C macros are generally not imported in Swift. Macros that define constants are
10331016
imported as readonly variables.

0 commit comments

Comments
 (0)