StrCmp
Description
Compare a Str against another string lexicographically.
Three call shapes via OVERLOAD + _Generic on other: StrCmp(s, other) – other is Str * or Zstr. StrCmp(s, other, other_len) – other is a fixed-length view (Zstr, size). The Str * overload is length-aware on both sides, so a string with an embedded NUL still compares correctly.
Parameters
| Name | Direction | Description |
|---|---|---|
s |
in | Str to compare. |
other |
in | Other string (Str * / Zstr). |
other_len |
in | Length of other for the 3-arg fixed-length form. |
Success
Returns 0 when equal, <0 when s < other, >0 when s > other. Neither string is modified.
Failure
Function cannot fail; the return value carries the order.
Usage example (Cross-references)
Usage examples (Cross-references)
#define JR_STR_KV(si, k, str) \
do { \
if (!StrCmp(&key, (k))) { \
Str UNPL(my_str) = StrInit(&alloc); \
si = JReadString((si), &UNPL(my_str)); \ });
if (StrCmp(&obj.name, "test", 4) == 0 && obj.value == 42 && obj.flag == true) {
WriteFmt(
"[DEBUG] Whitespace variations test passed - name: {}, value: {}, flag: {}\n", }
bool result = StrCmp(&output_clean, &expected_clean) == 0;
if (!result) { }
bool result = StrCmp(&output_clean, &expected_clean) == 0;
if (!result) { }
bool result = StrCmp(&output_clean, &expected_clean) == 0;
if (!result) { }
if (StrCmp(&data.name, "test", 4) != 0) {
WriteFmt("[DEBUG] Name check failed: expected 'test', got '");
for (size i = 0; i < StrLen(&data.name); i++) { }
if (StrCmp(&data.user.profile.name, "Alice", 5) != 0) {
WriteFmt("[DEBUG] Profile name check failed: expected 'Alice', got '");
for (u64 i = 0; i < StrLen(&data.user.profile.name); i++) { }
if (StrCmp(&data.status, "active", 6) != 0) {
WriteFmt("[DEBUG] Status check failed: expected 'active', got '");
for (size i = 0; i < StrLen(&data.status); i++) { });
if (StrCmp(&data.company.departments.engineering.head, "John", 4) != 0) {
WriteFmt("[DEBUG] Engineering head check failed: expected 'John', got '");
for (size i = 0; i < StrLen(&data.company.departments.engineering.head); i++) { }
if (StrCmp(&data.company.name, "TechCorp", 8) != 0) {
WriteFmt("[DEBUG] Company name check failed: expected 'TechCorp', got '");
for (size i = 0; i < StrLen(&data.company.name); i++) {
// Debug message check
if (StrCmp(&response.message, "Success", 7) != 0) {
WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
for (size i = 0; i < StrLen(&response.message); i++) { }
if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
for (size i = 0; i < StrLen(&sym->analysis_name); i++) { }
if (StrCmp(&sym->function_name, "main_func", 9) != 0) {
WriteFmt(
"[DEBUG] Function name check failed: expected 'main_func', got string of length {}\n", }
if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
for (size i = 0; i < StrLen(&sym->sha256); i++) { }
if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) { }
if (StrCmp(&info.name, "test_func", 9) != 0) {
WriteFmt("[DEBUG] Function name check failed: expected 'test_func', got '");
for (size i = 0; i < StrLen(&info.name); i++) { }
if (StrCmp(&info.name, "test_model", 10) != 0) {
WriteFmt("[DEBUG] Model name check failed: expected 'test_model', got '");
for (size i = 0; i < StrLen(&info.name); i++) { }
if (StrCmp(&result.binary_name, "test_binary", 11) != 0) {
WriteFmt("[DEBUG] Binary name check failed: expected 'test_binary', got '");
for (size i = 0; i < StrLen(&result.binary_name); i++) { }
if (StrCmp(&result.sha256, "abc123", 6) != 0) {
WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
for (size i = 0; i < StrLen(&result.sha256); i++) { }
if (StrCmp(&result.model_name, "test_model", 10) != 0) {
WriteFmt("[DEBUG] Model name check failed: expected 'test_model', got '");
for (size i = 0; i < StrLen(&result.model_name); i++) { }
if (StrCmp(&result.owned_by, "user1", 5) != 0) {
WriteFmt("[DEBUG] Owned by check failed: expected 'user1', got '");
for (size i = 0; i < StrLen(&result.owned_by); i++) { }
if (StrCmp(&response.message, "Success", 7) != 0) {
WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
for (size i = 0; i < StrLen(&response.message); i++) { }
if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
for (size i = 0; i < StrLen(&sym->analysis_name); i++) { }
if (StrCmp(&sym->function_name, "main_func", 9) != 0) {
WriteFmt(
"[DEBUG] Function name check failed: expected 'main_func', got string of length {}\n", }
if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
for (size i = 0; i < StrLen(&sym->sha256); i++) { }
if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) { }
if (StrCmp(&response.message, "Success", 7) != 0) {
WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
for (u64 i = 0; i < StrLen(&response.message); i++) { }
if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
for (size i = 0; i < StrLen(&sym->analysis_name); i++) { }
if (StrCmp(&sym->function_name, "main_func", 9) != 0) {
WriteFmt("[DEBUG] Function name check failed: expected 'main_func', got '");
for (size i = 0; i < StrLen(&sym->function_name); i++) { }
if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
for (size i = 0; i < StrLen(&sym->sha256); i++) { }
if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) {- In
Read.Simple.c:78:
});
if (StrCmp(&name, "Alice", 5) != 0) {
WriteFmt("[DEBUG] Name check failed: expected 'Alice', got '");
for (size i = 0; i < StrLen(&name); i++) {- In
Read.Simple.c:87:
}
if (StrCmp(&city, "New York", 8) != 0) {
WriteFmt("[DEBUG] City check failed: expected 'New York', got '");
for (size i = 0; i < StrLen(&city); i++) { }
if (StrCmp(&person.name, "Bob", 3) != 0) {
WriteFmt("[DEBUG] Person name check failed: expected 'Bob', got '");
for (size i = 0; i < StrLen(&person.name); i++) { }
if (StrCmp(&config.log_level, "INFO", 4) != 0) {
WriteFmt("[DEBUG] Log level check failed: expected 'INFO', got '");
for (size i = 0; i < StrLen(&config.log_level); i++) { Str *lang3 = &VecAt(&languages, 2);
if (StrCmp(lang1, "C", 1) != 0) {
WriteFmt("[DEBUG] Language 1 check failed: expected 'C', got '");
for (size i = 0; i < StrLen(lang1); i++) { }
if (StrCmp(lang2, "Python", 6) != 0) {
WriteFmt("[DEBUG] Language 2 check failed: expected 'Python', got '");
for (size i = 0; i < StrLen(lang2); i++) { }
if (StrCmp(lang3, "Rust", 4) != 0) {
WriteFmt("[DEBUG] Language 3 check failed: expected 'Rust', got '");
for (size i = 0; i < StrLen(lang3); i++) { });
if (StrCmp(&data.user.name, "Charlie", 7) != 0) {
WriteFmt("[DEBUG] User name check failed: expected 'Charlie', got '");
for (size i = 0; i < StrLen(&data.user.name); i++) { }
if (StrCmp(&data.user.email, "charlie@example.com", 19) != 0) {
WriteFmt("[DEBUG] User email check failed: expected 'charlie@example.com', got '");
for (size i = 0; i < StrLen(&data.user.email); i++) { }
if (StrCmp(&product.name, "Laptop", 6) != 0) {
WriteFmt("[DEBUG] Product name check failed: expected 'Laptop', got '");
for (size i = 0; i < StrLen(&product.name); i++) { Str *tag3 = &VecAt(&product.tags, 2);
if (StrCmp(tag1, "electronics", 11) != 0) {
WriteFmt("[DEBUG] Tag 1 check failed: expected 'electronics', got '");
for (size i = 0; i < StrLen(tag1); i++) { }
if (StrCmp(tag2, "computers", 9) != 0) {
WriteFmt("[DEBUG] Tag 2 check failed: expected 'computers', got '");
for (size i = 0; i < StrLen(tag2); i++) { }
if (StrCmp(tag3, "portable", 8) != 0) {
WriteFmt("[DEBUG] Tag 3 check failed: expected 'portable', got '");
for (size i = 0; i < StrLen(tag3); i++) {- In
RoundTrip.c:68:
// Helper function to compare persons
bool compare_persons(const TestPerson *a, const TestPerson *b) {
return a->id == b->id && StrCmp((Str *)&a->name, (Str *)&b->name) == 0 && a->age == b->age &&
a->is_active == b->is_active && a->salary == b->salary;
}- In
RoundTrip.c:75:
bool compare_configs(const TestConfig *a, const TestConfig *b) {
if (a->debug_mode != b->debug_mode || a->timeout != b->timeout ||
StrCmp((Str *)&a->log_level, (Str *)&b->log_level) != 0 ||
VecLen(&a->features) != VecLen(&b->features)) {
return false;- In
RoundTrip.c:81:
for (size i = 0; i < VecLen(&a->features); i++) {
if (StrCmp((Str *)&VecAt(&a->features, i), (Str *)&VecAt(&b->features, i)) != 0) {
return false;
}- In
RoundTrip.c:133:
// Compare values
if (original.count == parsed.count && original.temperature == parsed.temperature &&
original.enabled == parsed.enabled && StrCmp(&original.message, &parsed.message) == 0) {
WriteFmtLn("[DEBUG] Simple round-trip test passed");
} else {- In
RoundTrip.c:338:
// Compare values
if (StrLen(&parsed.empty) == StrLen(&original.empty) && StrCmp(&original.simple, &parsed.simple) == 0 &&
StrCmp(&original.with_spaces, &parsed.with_spaces) == 0 &&
StrCmp(&original.with_special, &parsed.with_special) == 0) {- In
RoundTrip.c:339:
// Compare values
if (StrLen(&parsed.empty) == StrLen(&original.empty) && StrCmp(&original.simple, &parsed.simple) == 0 &&
StrCmp(&original.with_spaces, &parsed.with_spaces) == 0 &&
StrCmp(&original.with_special, &parsed.with_special) == 0) {
WriteFmtLn("[DEBUG] String round-trip test passed");- In
RoundTrip.c:340:
if (StrLen(&parsed.empty) == StrLen(&original.empty) && StrCmp(&original.simple, &parsed.simple) == 0 &&
StrCmp(&original.with_spaces, &parsed.with_spaces) == 0 &&
StrCmp(&original.with_special, &parsed.with_special) == 0) {
WriteFmtLn("[DEBUG] String round-trip test passed");
} else {- In
RoundTrip.c:431:
if (StrLen(VecPtrAt(&original_strings, i)) != StrLen(VecPtrAt(&parsed_strings, i)) ||
(StrLen(VecPtrAt(&original_strings, i)) &&
StrCmp(VecPtrAt(&original_strings, i), VecPtrAt(&parsed_strings, i)) != 0)) {
strings_match = false;
break;- In
Parse.c:26:
result = result && (MapPairCount(&cfg) == 3);
result = result && KvConfigContains(&cfg, "host");
result = result && host && StrCmp(host, "localhost") == 0;
result = result && KvConfigGetI64(&cfg, "port", &port) && (port == 8080);
result = result && KvConfigGetBool(&cfg, "debug", &debug) && debug;- In
Parse.c:59:
result = result && (StrIterIndex(&si) == StrIterLength(&si));
result = result && (MapPairCount(&cfg) == 4);
result = result && path && StrCmp(path, "/srv/my app") == 0;
result = result && user && StrCmp(user, "root") == 0;
result = result && greet && StrCmp(greet, "hello world") == 0;- In
Parse.c:60:
result = result && (MapPairCount(&cfg) == 4);
result = result && path && StrCmp(path, "/srv/my app") == 0;
result = result && user && StrCmp(user, "root") == 0;
result = result && greet && StrCmp(greet, "hello world") == 0;
result = result && empty && (StrLen(empty) == 0);- In
Parse.c:61:
result = result && path && StrCmp(path, "/srv/my app") == 0;
result = result && user && StrCmp(user, "root") == 0;
result = result && greet && StrCmp(greet, "hello world") == 0;
result = result && empty && (StrLen(empty) == 0);- In
Parse.c:88:
result = result && (StrLen(&host_copy) > 0);
result = result && (StrBegin(&host_copy) != StrBegin(stored_host));
result = result && (StrCmp(&host_copy, "localhost") == 0);
result = result && (StrCmp(stored_host, "localhost") == 0);- In
Parse.c:89:
result = result && (StrBegin(&host_copy) != StrBegin(stored_host));
result = result && (StrCmp(&host_copy, "localhost") == 0);
result = result && (StrCmp(stored_host, "localhost") == 0);
StrBegin(&host_copy)[0] = 'L';- In
Parse.c:93:
StrBegin(&host_copy)[0] = 'L';
result = result && (StrCmp(&host_copy, "Localhost") == 0);
result = result && (StrCmp(stored_host, "localhost") == 0);- In
Parse.c:94:
result = result && (StrCmp(&host_copy, "Localhost") == 0);
result = result && (StrCmp(stored_host, "localhost") == 0);
StrDeinit(&host_copy);- In
Str.Ops.c:23:
// Test string comparison functions
bool test_str_cmp(void) {
WriteFmt("Testing StrCmp variants\n");
DefaultAllocator alloc = DefaultAllocatorInit();- In
Str.Ops.c:33:
// Test StrCmp with equal strings
int cmp1 = StrCmp(&s1, &s2);
bool result = (cmp1 == 0);- In
Str.Ops.c:37:
// Test StrCmp with different strings (H < W in ASCII)
int cmp2 = StrCmp(&s1, &s3);
result = result && (cmp2 < 0);- In
Str.Ops.c:41:
// Test StrCmp with string prefix - ZstrCompare compares the entire strings
int cmp3 = StrCmp(&s1, &s4);
result = result && (cmp3 < 0); // "Hello" comes before "Hello World" lexicographically
- In
Str.Ops.c:45:
// Test StrCmp (Cstr key, key_len)
int cmp4 = StrCmp(&s1, "Hello", 5);
result = result && (cmp4 == 0);- In
Str.Ops.c:48:
result = result && (cmp4 == 0);
int cmp5 = StrCmp(&s1, "World", 5);
result = result && (cmp5 != 0);- In
Io.Read.c:328:
Str expected = StrInitFromZstr("Hello", &alloc);
success = success && (StrCmp(&s, &expected) == 0);
StrDeinit(&expected);
StrClear(&s);- In
Io.Read.c:336:
expected = StrInitFromZstr("Hello, World!", &alloc);
success = success && (StrCmp(&s, &expected) == 0);
StrDeinit(&expected);- In
Io.Read.c:375:
Str expected = StrInitFromZstr("Alice", &alloc);
success = success && (StrCmp(&name, &expected) == 0);
StrDeinit(&expected);
StrClear(&name);- In
Io.Read.c:386:
expected = StrInitFromZstr("Bob", &alloc);
success = success && (StrCmp(&name, &expected) == 0);
StrDeinit(&expected);- In
Io.Read.c:579:
StrReadFmt(z, "{c}", str_val);
Str expected = StrInitFromZstr("Hello", &alloc);
bool str_pass = (StrCmp(&str_val, &expected) == 0);
WriteFmt("str_val test: comparing with 'Hello', pass = {}\n", str_pass ? "true" : "false");
success = success && str_pass;- In
Io.Read.c:589:
StrReadFmt(z, "{cs}", str_val);
expected = StrInitFromZstr("World", &alloc);
bool quoted_str_pass = (StrCmp(&str_val, &expected) == 0);
WriteFmt("quoted str_val test: comparing with 'World', pass = {}\n", quoted_str_pass ? "true" : "false");
success = success && quoted_str_pass;- In
Io.Read.c:626:
// Should read "hello" (stops at first space)
Str expected = StrInitFromZstr("hello world", &alloc);
bool test1_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'hello', Pass: {}\n\n", test1_pass ? "true" : "false");
success = success && test1_pass;- In
Io.Read.c:651:
// Should read "hello" (stops at first space)
Str expected = StrInitFromZstr("hello", &alloc);
bool test1_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'hello', Pass: {}\n\n", test1_pass ? "true" : "false");
success = success && test1_pass;- In
Io.Read.c:676:
// Should read "HELLO" (stops at first space)
Str expected = StrInitFromZstr("HELLO WORLD", &alloc);
bool test2_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'HELLO', Pass: {}\n\n", test2_pass ? "true" : "false");
success = success && test2_pass;- In
Io.Read.c:696:
WriteFmt("Input: '{}', Output: '{} {}'", in, result1, result2);
bool test2_pass = (StrCmp(&result1, "HELLO") == 0);
test2_pass &= (StrCmp(&result2, "WORLD") == 0);
WriteFmt("Expected: 'HELLO WORLD', Pass: {}\n\n", test2_pass ? "true" : "false");- In
Io.Read.c:697:
bool test2_pass = (StrCmp(&result1, "HELLO") == 0);
test2_pass &= (StrCmp(&result2, "WORLD") == 0);
WriteFmt("Expected: 'HELLO WORLD', Pass: {}\n\n", test2_pass ? "true" : "false");
success = success && test2_pass;- In
Io.Read.c:719:
WriteFmt("Input: '{}', Output: '{}{}'", in, result1, result2);
bool test2_pass = (StrCmp(&result1, "HELLO") == 0);
test2_pass &= (StrCmp(&result2, " WORLD MIGHTY MISRA") == 0); // notice the extra space
WriteFmt("Expected: 'HELLO WORLD MIGHTY MISRA', Pass: {}\n\n", test2_pass ? "true" : "false");- In
Io.Read.c:720:
bool test2_pass = (StrCmp(&result1, "HELLO") == 0);
test2_pass &= (StrCmp(&result2, " WORLD MIGHTY MISRA") == 0); // notice the extra space
WriteFmt("Expected: 'HELLO WORLD MIGHTY MISRA', Pass: {}\n\n", test2_pass ? "true" : "false");
success = success && test2_pass;- In
Io.Read.c:745:
// Should read "mixed case" (converts the entire quoted string)
Str expected = StrInitFromZstr("mixed case", &alloc);
bool test3_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'mixed case', Pass: {}\n\n", test3_pass ? "true" : "false");
success = success && test3_pass;- In
Io.Read.c:770:
// Should read "ABC123XYZ" (only letters are converted, numbers unchanged)
Str expected = StrInitFromZstr("ABC123XYZ", &alloc);
bool test4_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'ABC123XYZ', Pass: {}\n\n", test4_pass ? "true" : "false");
success = success && test4_pass;- In
Io.Read.c:795:
// Should read "Hello" (stops at first space, no case conversion)
Str expected = StrInitFromZstr("Hello World", &alloc);
bool test5_pass = (StrCmp(&result, &expected) == 0);
WriteFmt("Expected: 'Hello World', Pass: {}\n\n", test5_pass ? "true" : "false");
success = success && test5_pass; str_obj = BitVecToStr(&bv);
result = result && (StrLen(&str_obj) == 1);
result = result && (StrCmp(&str_obj, "1", 1) == 0);
StrDeinit(&str_obj);- In
JSON.h:271:
#define JR_STR_KV(si, k, str) \
do { \
if (!StrCmp(&key, (k))) { \
Str UNPL(my_str) = StrInit(); \
si = JReadString((si), &UNPL(my_str)); \- In
JSON.h:316:
#define JR_INT_KV(si, k, i) \
do { \
if (!StrCmp(&key, (k))) { \
i64 UNPL(my_int) = 0; \
si = JReadInteger((si), &UNPL(my_int)); \- In
JSON.h:361:
#define JR_FLT_KV(si, k, f) \
do { \
if (!StrCmp(&key, (k))) { \
f64 UNPL(my_flt) = 0; \
si = JReadFloat((si), &UNPL(my_flt)); \- In
JSON.h:406:
#define JR_BOOL_KV(si, k, b) \
do { \
if (!StrCmp(&key, (k))) { \
bool UNPL(my_b) = 0; \
si = JReadBool((si), &UNPL(my_b)); \- In
JSON.h:658:
#define JR_OBJ_KV(si, k, reader) \
do { \
if (!StrCmp(&key, (k))) { \
JR_OBJ(si, reader); \
} \- In
JSON.h:684:
#define JR_ARR_KV(si, k, reader) \
do { \
if (!StrCmp(&key, (k))) { \
JR_ARR(si, reader); \
} \
Last updated on