Interoperability with C, Objective-C and C++
|
This section documents the Swift 6 language mode as shipped by Swift 6.3, as published in The Swift Programming Language at docs.swift.org, which is the reference these pages are written and verified against. 6.4-beta-only features are always flagged as such — never presented as baseline. This content was generated with the assistance of AI and should be verified against docs.swift.org before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Swift was designed from the start to sit alongside C and Objective-C, and more recently gained first-class C++ interop as well. All three follow the same underlying idea — a compiler-generated importer maps foreign declarations into their nearest Swift equivalent — but each language’s importer has its own rules, gaps, and annotations for smoothing over the differences.
The Clang Importer: C into Swift
When a Swift target imports a C header (directly, or via a bridging header — see Objective-C Interop
below), the Clang importer translates it, largely following the same conventions
Objective-C’s own importer uses for its
NS-prefixed types:
| C construct | Imported as |
|---|---|
|
|
|
|
|
A Swift struct exposing every member at the same memory offset — reading one after writing another is undefined behavior, exactly as in C. |
|
A Swift |
|
|
|
A Swift closure type, |
|
A global |
Preprocessor conditionals ( |
Resolved by Clang before Swift ever sees the header — Swift never sees the macro itself, only the branch Clang picked. |
// Point.h: struct Point { double x, y; }; double distance(struct Point a, struct Point b);
var origin = Point(x: 0, y: 0) // memberwise init, synthesized by the importer
let d = distance(origin, Point(x: 3, y: 4)) // free C functions import as free Swift functions
See C: Structures, Unions and Type
Aliases and C: Pointers for these constructs on the C side, and
Memory Safety and Unsafe Pointers for
working with the Unsafe*Pointer family an imported C API hands back.
Module Maps and System-Library Targets in SwiftPM
A plain C header has no notion of a Swift "module" — a module map (module.modulemap) is what tells the
Clang importer which headers belong to which module and how to expose them:
// Sources/CZlib/module.modulemap
module CZlib [system] {
header "shim.h"
link "z"
export *
}
// Package.swift
let package = Package(
name: "MyTool",
targets: [
.systemLibrary(name: "CZlib", pkgConfig: "zlib"), // wraps a C library already on the system
.target(name: "MyTool", dependencies: ["CZlib"])
]
)
A systemLibrary target wraps a C library that is expected to already be installed (via pkgConfig, or a
providers list naming the system package manager’s package name), rather than one SwiftPM builds itself; an
ordinary .target with a Sources/<Name>/include/.h layout works the same way for a C library that *is built
from source as part of the package. See
Swift Package Manager for package targets in
general.
Objective-C Interop
| Mechanism | Purpose |
|---|---|
Bridging header ( |
Exposes chosen Objective-C headers to every Swift file in an
app target, with no |
|
Exposes a Swift declaration (or every member of a class) to Objective-C, which
requires inheriting from |
|
Renames an Objective-C declaration as seen from Swift. |
Nullability ( |
Becomes |
Lightweight generics ( |
Becomes a properly parameterized Swift collection
( |
|
Imported as |
// Objective-C: - (void)fetchUserWithID:(NSInteger)userID
// completion:(void (^)(User * _Nullable, NSError * _Nullable))completion;
let user = try await service.fetchUser(id: 42) // imported as an `async throws` function -- no completion handler
An Objective-C API following the completion:(void (^)(Result, NSError )) pattern is imported as an async
function automatically, unifying it with native Swift concurrency (see
Async/Await and Tasks) with no manual bridging.
Exposing Swift *to Objective-C is the mirror image: a class must inherit NSObject and mark members @objc
(or @objcMembers), and the compiler emits a <Module>-Swift.h header for Objective-C files to #import.
This reference’s Objective-C Reference covers this direction in much greater depth, in particular Swift Interoperability (the bridging header and generated header mechanics, the full table of imported constructs, and mixed-language project practices) and Lightweight Generics and Nullability (the annotations that produce a clean Swift API).
C++ Interop
// Package.swift
.target(
name: "MySwiftTarget",
swiftSettings: [.interoperabilityMode(.Cxx)] // enables -cxx-interoperability-mode=default
)
C++ interop is opt-in per target, via -cxx-interoperability-mode=default (or .interoperabilityMode(.Cxx)
in a SwiftPM manifest). Once enabled:
// Point.hpp: struct Point { double x, y; double distance(const Point& other) const; };
var origin = Point()
origin.x = 0
origin.y = 0
let other = Point(x: 3, y: 4) // {cpp} constructors are imported too
origin.distance(other) // member functions become Swift methods
var vec = std.vector<Int32>() // std::vector<int> imported as a Swift-usable generic type
vec.push_back(1)
vec.push_back(2)
for value in vec { print(value) } // std::vector conforms to Swift's Sequence when interop is on
| C++ construct | Imported as |
|---|---|
A C++ class/struct |
A Swift struct or class exposing its public members and methods. |
References ( |
Mapped to Swift’s own parameter-passing conventions; a |
|
Usable directly from Swift, with |
C++ templates |
Only concrete instantiations actually used from Swift are imported — an uninstantiated template has nothing for Swift to bind to. |
Exposing Swift to C++ works in the same target, once interop is enabled — a C++ file can #include the
generated Swift header and call exposed Swift functions and methods directly, though (as of Swift 6.3) the
Swift-to-C++ direction supports a narrower set of Swift features than the C++-to-Swift direction does. See
C++: Templates and
C++: Containers for these constructs on the C++ side.
This reference’s C++ Reference and its own Memory Management and Smart Pointers page cover ownership and lifetime rules relevant to values crossing the boundary.
The Three References, Side by Side
For C, C++ and Objective-C in their own right — rather than as seen through Swift’s importer — see:
-
C Reference — in particular Pointers, Structures, Unions and Type Aliases, and Preprocessor and Macros.
-
C++ Reference — in particular Templates and Containers.
-
Objective-C Reference — in particular Swift Interoperability, the page this one most directly complements.
See Also
-
Memory Safety and Unsafe Pointers — the
Unsafe*Pointerfamily an imported C API commonly hands back. -
Async/Await and Tasks — how Objective-C completion-handler APIs import as
asyncfunctions. -
Swift Package Manager —
systemLibrarytargets and package manifests in full.