C Bindings
The C bindings are distributed as a zip file with the following directory layout:
- single header file in
/include/dnp3.h
- cmake find package script in
/cmake/
- platform specific shared libraries in
/lib/<platform>
- 3rd party license information in
/lib/licenses.txt
#
CMake UsageMake the find package script discoverable by adding it to the prefix path. Then call find_package
:
Then declare a dependency on the package:
#
MappingMany of the concepts built into higher-level languages are simply design patterns or idioms in C. When you see these higher levels patterns discussed in this guide, you can use the idioms here to understand how they map to C.
#
ClassesC doesn't have classes with restricted member visibility. Instead, you can use opaque types to hide implementation details:
You can then define constructors
and destructors
as functions:
Class "member functions" are simply functions that take a pointer to the opaque type as the first argument:
#
InterfacesFunction polymorphism in C is accomplished using function pointers. Interfaces are simply collections of functions pointers along with some optional context. For example, consider the following logging "interface" in the library:
ctx
is an opaque pointer to some state information required by the interface. It is passed into every method as the final argument.on_destroy
is the destructor that cleans up thectx
on_message
is a function pointer used to dispatch a log message.
This interface only contains a single method, but other interfaces contain a number of methods.
tip
If your implementation of an interface is stateless, you can initialize ctx
and on_destroy
to NULL. C99 struct initialization syntax
will do this by default if you don't specify a value for these fields.
#
IteratorsCollections in the C bindings are always implemented as an opaque iterator type. You can think of them as a class with a single "next" method. Consider an iterator over bool values:
If you are given this iterator in a callback you can process the values in a loop:
warning
You should never use an iterator outside of the callback. Frequently, the iterator points to memory on the call stack and will result in undefined behavior if used after the callback has completed.
#
Error HandlingError handling in the C API is performed using error codes. An error code is always an enum value with the first value equal to zero and indicating success.
Consider an error enum and a function that parses a string as an int
that can fail:
When a function that can fail needs to return a value, it always does so using an out parameter as the last argument. User code should always check returned error values:
note
Every enum generated by the C code generator also has a generated *_to_string
helper method to aid in debugging.