Principle:Tencent Ncnn C Language Binding
| Knowledge Sources | |
|---|---|
| Domains | API_Design, Foreign_Function_Interface |
| Last Updated | 2026-02-09 19:00 GMT |
Overview
Exposing a C++ inference framework through an opaque-handle C API to provide ABI stability and enable consumption from any language with a C foreign function interface.
Description
C language binding is the practice of wrapping a C++ library behind a pure C interface so that callers interact only with opaque pointer types (handles) and free functions, never with C++ classes, templates, virtual tables, or name-mangled symbols. This solves several problems simultaneously: it provides a stable Application Binary Interface (ABI) that does not break when the internal C++ implementation changes; it enables consumption from languages that only support C FFI (Python ctypes, Rust extern "C", Go cgo, C# P/Invoke, Java JNI); and it avoids C++ runtime dependency issues when linking across different compilers or standard library versions.
The pattern works by defining opaque typedefs (e.g., typedef struct __ncnn_net_t* ncnn_net_t) whose internal layout is hidden from the caller. All operations are expressed as free functions that accept and return these opaque handles. Resource management follows a create/destroy pair convention: ncnn_net_create() allocates and returns a handle, ncnn_net_destroy() frees it. Between creation and destruction, the caller invokes setter/getter functions and extraction operations. The C header is wrapped in extern "C" { } when compiled by a C++ compiler, ensuring symbols use C linkage.
Usage
Apply this principle when a C++ inference library must be callable from non-C++ languages or when downstream consumers require a guaranteed-stable ABI across library version upgrades. It is essential for embedding inference capabilities in mobile applications, game engines, or scripting language runtimes.
Theoretical Basis
Opaque handle pattern:
// Public header -- caller sees only an opaque pointer
typedef struct __ncnn_net_t* ncnn_net_t;
typedef struct __ncnn_mat_t* ncnn_mat_t;
typedef struct __ncnn_extractor_t* ncnn_extractor_t;
typedef struct __ncnn_option_t* ncnn_option_t;
Create / configure / use / destroy lifecycle:
// 1. Create resources
ncnn_net_t net = ncnn_net_create();
ncnn_option_t opt = ncnn_option_create();
ncnn_option_set_num_threads(opt, 4);
ncnn_net_set_option(net, opt);
// 2. Load model
ncnn_net_load_param(net, "model.param");
ncnn_net_load_model(net, "model.bin");
// 3. Run inference
ncnn_mat_t in = ncnn_mat_from_pixels_resize(data, ...);
ncnn_extractor_t ex = ncnn_extractor_create(net);
ncnn_extractor_input(ex, "data", in);
ncnn_mat_t out;
ncnn_extractor_extract(ex, "prob", &out);
const float* result = ncnn_mat_get_data(out);
// 4. Destroy resources (reverse order)
ncnn_mat_destroy(out);
ncnn_mat_destroy(in);
ncnn_extractor_destroy(ex);
ncnn_option_destroy(opt);
ncnn_net_destroy(net);
extern "C" linkage guard:
#ifdef __cplusplus
extern "C" {
#endif
NCNN_EXPORT ncnn_net_t ncnn_net_create(void);
NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net);
// ... all other C API functions ...
#ifdef __cplusplus
}
#endif