libcpr
is a public domain backport of the core data structures and
algorithms from the C++11 standard library to C.
- Implements a straightforward mapping from C++ to C, with consistent naming.
- No runtime dependencies other than C99 and the system's C++ standard library.
- No build prerequisites beyond the Autotools toolchain and a C++11 compiler.
- Compatible with Clang and GCC, or indeed any standard C++11 implementation.
- Plays nice with others: all exported symbols are prefixed with
cpr_
. - 100% free and unencumbered public domain software, usable in any context and for any purpose.
The C standard library is severely deficient in useful data structures essential to modern programming practice. Consequently, most non-trivial C programs and shared libraries include one-off implementations of even the most elementary data structures such as dynamic arrays and hash tables. This harms programmer productivity, bloats the sizes of binaries, wastes machine resources, and inevitably introduces unnecessary bugs--including security vulnerabilities.
The alternative to rolling your own data structures has thus far been to pull in a large, all-purpose library dependency such as GLib. The problem with this approach is that you just wanted a hash table, but you got the kitchen sink with an XML parser thrown in for good measure. These all-purpose libraries have a huge footprint and can be difficult to install, ensuring that your potential user base will prefer competing projects who do roll their own data structures.
libcpr
is a new take on an old problem. Given that every modern desktop
and server system today is guaranteed to already have not merely the C
standard library but also the C++ standard library, libcpr
provides the
until-now missing glue to access that latter library from pure C. The C++
standard library contains the basic data structures and algorithms needed
for most common programming tasks, and adds no bloat since it's already
installed on the system regardless.
The target audience for this library is twofold. On the one hand, C
programmers who need a robust, reliable, and stable implementation of the
provided data structures will certainly benefit from libcpr
. On the
other, C++ programmers who find themselves, for whatever reason, visiting
plain-C territory will appreciate having their standard data structures at
hand with a trivial learning curve to applying existing STL know-how.
This table summarizes the data types that are implemented at present:
Header | Interface | Description | Status |
---|---|---|---|
<cpr/string.h> | std::string | Dynamic strings | Usable |
<cpr/vector.h> | std::vector | Dynamic arrays | WIP |
The <cpr/string.h>
interface implements dynamic strings.
cpr_string_t* string = cpr_string("Hello, world!\n");
The <cpr/vector.h>
interface implements dynamic arrays.
cpr_vector_t* vector = cpr_vector_of_strings(...);
printf("libcpr compile version: %hu.%hu.%hu\n", CPR_VERSION_MAJOR, CPR_VERSION_MINOR, CPR_VERSION_PATCH); printf("libcpr runtime version: %hu.%hu.%hu\n", cpr_version_major, cpr_version_minor, cpr_version_patch);
- Catches all C++ exceptions and translates them into C error codes.
- Carefully differentiates logic errors, runtime errors, and fatal errors.
- Adheres to uniform naming conventions patterned after the C++ standard library.
The naming conventions and indeed symbol the symbol names themselves are closely patterned after those of the C++ standard library.
Since C does not support function overloading, C++ standard library methods
which provide multiple overloads are differentiated in libcpr
by
suffixing the corresponding function names with a disambiguating string,
usually a type name. For example std::string::append()
provides multiple
overloads; the corresponding libcpr
functions are provided as
cpr_string_append_char()
for a character argument,
cpr_string_append_str()
for a C string argument, and so on.
All constructor functions return pointers to opaque structures allocated on
the program heap using the system's standard calloc()
facility. The
library provides corresponding deallocation functions to destruct and free
these pointers.
Given that all object pointers are to opaque structures, no direct access to any structure fields is permitted or afforded; all access is procedural. This encapsulation facilitates and ensures ABI stability as the library evolves.
In addition, for expert users, a so-called "unsafe" mode is provided wherein
libcpr
structures can be allocated directly on the stack using the
system's alloca()
facility. This is more efficient than heap allocation,
but not generally safe since it will certainly break the ABI should the
structure sizes change in a future libcpr
release. Caveat utilitor.
This library makes a careful distinction between three different classes of error conditions:
- Logic errors, triggered using
cpr_logic_error()
. Errors of this class are thrown due to programming errors where the function interfaces are used in violation of documented preconditions. A common strategy for handling this class of error conditions is to abort the program with a core dump, facilitating introspection to locate and remedy the bug. - Fatal errors, triggered using
cpr_fatal_error()
. Errors of this class are thrown due to the exhaustion of critical system resources, in particular available memory (ENOMEM
), or due to attempts to exceed applicable system resource limits. A typical strategy for handling this class of error conditions is to terminate the program with a descriptive error message. More robust programs and shared libraries may wish to implement another strategy, such as retrying the operation after first letting most of the call stack unwind in order to free up scarce resources. - Runtime errors, triggered using
cpr_runtime_error()
. Errors of this class are thrown as a matter of course to indicate various exceptional conditions. These conditions are generally recoverable, and robust programs will take care to correctly handle them.
Note
The distinction between logic errors and runtime errors mirrors that
found in the C++11 standard library, where the <stdexcept>
header
defines the standard exception base classes std::logic_error
and
std::runtime_error
. The standard exception class std::bad_alloc
,
on the other hand, is a representative example of a fatal error.
Note
Older releases may work, but are not actively tested for.
$ ./autogen.sh $ ./configure # on Linux $ ./configure --with-stdlib=libc++ # on FreeBSD / Mac OS X $ make $ sudo make install $ sudo ldconfig # on Linux
Find this project at: GitHub, Bitbucket, Open Hub, Freecode, SourceForge, Travis CI, Wercker, Coverity Scan, Twitter, Tumblr, and COD5.
This project is part of the DRY initiative.
If you found this software useful and would like to encourage its maintenance and further development, please consider making a $5 donation to the author(s) via Gratipay or Bitcoin.
This is free and unencumbered public domain software. For more information,
see http://unlicense.org/ or the accompanying UNLICENSE
file.