This is a type-safe, header-only implementation of a std::basic_string
-like string in plain C code.
It can be considered an offshoot of the c-vector library and is intended to be binary compatible with it. Many sequences of the c-string
library essentially correspond to the c-vector
library code. All credits go to eteran and contributors.
While the c-vector
library implements macros to emulate methods of a std::vector
, the c-string
library is specialized for null-terminated strings of characters. Its macros emulate the subset of std::basic_string
methods that can't be trivially mimicked using functions of the C string library. A few additional features are implemented that don't have an equivalent for a std::basic_string
.
Just like the cvector
, a cstring
is prefixed with metadata, in the tradition of a length-prefixed string implementation.
The members of the cstring
metadata are found at the same offset as those of a cvector
. They count all characters (incl. the terminating null) which makes a cstring
interchangeable with a cvector
of the same set of consecutive characters. Unlike the cvector
macros (and as is usual for strings) the cstring
macros, which return size and capacity, do not count the string terminator.
The user is given a pointer to the first character of the actual string. This way a cstring
can be used with the C string and I/O library functions that don't modify its content, as well as whith those of the platform API.
Example:
#include "cstring.h"
#include <stdio.h>
int main(void) {
// Declaration of a null-string. The initialization with NULL is critical.
cstring_string_type(char) str = NULL;
// Assign string "abc".
cstring_assign(str, "abc", 3);
printf("1)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Append string "hi".
cstring_append(str, "hi", 2);
printf("2)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Insert string "defg" at offset 3 (between 'c' and 'h').
cstring_insert(str, 3, "defg", 4);
printf("3)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Erase 4 characters at offset 1.
cstring_erase(str, 1, 4);
printf("4)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Add an 'x' at the end of the string.
cstring_push_back(str, 'x');
printf("5)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Replace two characters at offset 3 with three 'z' characters.
cstring_replace(str, 3, 2, "zzz", 3);
printf("6)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Copy a 4-character substring from offset 2.
cstring_string_type(char) str2 = NULL;
cstring_substring(str, 2, 4, str2);
printf("7)\nString2: %s\nLength: %zu\nCapacity: %zu\n\n", str2, cstring_length(str2), cstring_capacity(str2));
// Free allocated memory.
cstring_free(str2);
cstring_free(str);
return 0;
}
std::basic_string | cstring |
---|---|
std::basic_string<type> str{}; |
cstring_string_type(type) str = NULL; 1,cstring_literal(name, type, lit) 2,cstring_init(name, type) 3 |
Destructor | cstring_free(str) |
str.assign(s, count) |
cstring_assign(str, s, count) |
str.at(pos) |
cstring_at(str, pos) |
str[pos] |
str[pos] |
str.front() |
cstring_front(str) |
str.back() |
cstring_back(str) |
str.data() , str.c_str() |
str |
str.begin() |
cstring_begin(str) |
str.end() |
cstring_end(str) |
str.empty() |
cstring_empty(str) |
str.size() , str.length() |
cstring_size(str) , cstring_length(str) |
std::basic_string<type>::max_size() |
cstring_max_size(type) |
str.reserve(n) |
cstring_reserve(str, n) |
str.capacity() |
cstring_capacity(str) |
str.shrink_to_fit() |
cstring_shrink_to_fit(str) |
N/A | cstring_unsafe_set_size(str, size) 4 |
str.clear() |
cstring_clear(str) |
str.insert(index, s, count) |
cstring_insert(str, index, s, count) |
str.erase(index, count) |
cstring_erase(str, index, count) |
str.push_back(ch) |
cstring_push_back(str, ch) |
str.pop_back() |
cstring_pop_back(str) |
str.append(s, count) |
cstring_append(str, s, count) |
str.replace(pos, count, s, count2) |
cstring_replace(str, pos, count, s, count2) |
from.copy(to, npos, 0) |
cstring_copy(from, to) 5 |
str.resize(count, ch) |
cstring_resize(str, count, ch) |
str.swap(other) |
cstring_swap(str, other) |
N/A | cstring_trim(str, value, mode) 6 |
N/A | cstring_fix(str, length, value, mode) 7 |
N/A | cstring_reverse(str) 8 |
offset = str.find(s, pos, count) |
cstring_find(str, pos, s, count, offset) |
offset = str.rfind(s, pos, count) |
cstring_rfind(str, pos, s, count, offset) |
to = from.substring(pos, count) |
cstring_substring(from, pos, count, to) |
Footnotes
-
Initializes a NULL string. Nothing similar for
std::basic_string
. ↩ -
Declares a static cstring literal of
const type
. This is comparable with a C++20constexpr std::basic_string
. ↩ -
Allocates and initializes a zero-length string. ↩
-
Manually updates the size property after an update of the string buffer in a third party API. ↩
-
This creates a duplicate of the string. For copying a substring see
cstring_substring()
. ↩ -
Removes contiguous occurrences of the specified character from the begin and/or the end of a cstring. ↩
-
Updates the cstring to a fixed length by either padding or shortening. ↩
-
Reverses the character order in the cstring. ↩