[update] 添加了 ek_str 模块,用于支持实现字符串处理#7
Conversation
There was a problem hiding this comment.
Pull request overview
该 PR 在 utils 层新增 ek_str 字符串处理模块,并把对应的测试用例接入到 Test 工程中,通过 ek_conf.h 增加模块开关以控制编译启用。
Changes:
- 新增
ek_str模块(create/free/append/append_fmt/slice/cat/cmp 等 API) - 在
ek_conf.h增加EK_STR_ENABLE配置项并默认启用 - 新增并接入
str_test测试用例到 Test 主程序
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| ek_conf.h | 增加 EK_STR_ENABLE 模块开关并默认开启 |
| L2_Core/utils/inc/ek_str.h | 新增字符串模块对外头文件与 API 声明 |
| L2_Core/utils/src/ek_str.c | 新增字符串模块实现 |
| Test/test.h | 引入 ek_str.h 并声明 str_test |
| Test/str_test.c | 新增字符串模块测试用例 |
| Test/main.c | 在测试主程序中调用 str_test() |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| memcpy(new_s->buf, s->buf + start, new_len); | ||
| new_s->len = new_len; | ||
| new_s->cap = new_len; |
There was a problem hiding this comment.
ek_str_slice 分配了 new_len + 1 字节并写入终止符,但把 new_s->cap 设为 new_len,与其它地方把 cap 当作“可用 buffer 字节数(含 \0)”的用法不一致,会导致后续扩容判断异常(至少会多一次不必要的 realloc)。建议让 cap 与实际分配保持一致。
| new_s->cap = new_len; | |
| new_s->cap = new_len + 1; |
| } | ||
|
|
||
| bool ek_str_append(ek_str_t *s, const char *str) | ||
| { |
There was a problem hiding this comment.
ek_str_append 直接对 str 调用 strlen(str);如果调用方传入 NULL 会产生未定义行为/崩溃。建议在这里对 str 做断言或按 ek_str_append_len 的约定将 NULL 视为 no-op。
| { | |
| { | |
| // 按照 ek_str_append_len 的约定:传入 NULL 视为 no-op | |
| if (str == NULL) | |
| { | |
| return true; | |
| } |
| ek_str_t *ek_str_create(const char *str); | ||
| void ek_str_free(ek_str_t *s); | ||
| void ek_str_clear(ek_str_t *s); | ||
|
|
||
| bool ek_str_append_len(ek_str_t *s, const char *str, uint32_t len); | ||
| bool ek_str_append(ek_str_t *s, const char *str); | ||
| bool ek_str_append_fmt(ek_str_t *s, const char *fmt, ...); | ||
|
|
||
| bool ek_str_cat(ek_str_t *dst, ek_str_t *src); | ||
| ek_str_t *ek_str_slice(const ek_str_t *s, int32_t start, int32_t end); | ||
| const char *ek_str_get_cstring(ek_str_t *s); | ||
|
|
||
| uint32_t ek_str_get_len(ek_str_t *s); | ||
| uint32_t ek_str_get_cap(ek_str_t *s); | ||
|
|
||
| int ek_str_cmp(ek_str_t *s1, ek_str_t *s2); | ||
| int ek_str_ncmp(ek_str_t *s1, ek_str_t *s2, size_t n); | ||
|
|
There was a problem hiding this comment.
ek_str.h 声明了对外函数接口,但没有像其它 utils API 头文件那样加 #ifdef __cplusplus / extern "C" 包裹,C++ 工程中包含该头会发生符号名改编导致链接失败。建议参照 L2_Core/utils/inc/ek_mem.h:15-18、ek_stack.h:42-45 的写法补上。
|
|
||
| char *buf = NULL; | ||
|
|
||
| if (s->buf == NULL) buf = ek_malloc(len); |
There was a problem hiding this comment.
_ek_str_ensure_cap 在 s->buf == NULL 分支用 ek_malloc(len) 分配,但随后把 s->cap 设为 new_cap。当 new_cap > len 时会导致 cap 与实际分配大小不一致,后续写入可能越界。建议这里按 new_cap 分配(并保持 cap 与实际 buffer 大小一致)。
| if (s->buf == NULL) buf = ek_malloc(len); | |
| if (s->buf == NULL) buf = ek_malloc(new_cap); |
| INDEX_CLAMP(start, len); | ||
| INDEX_CLAMP(end, len); | ||
|
|
||
| if (start == end) return ek_str_create(""); |
There was a problem hiding this comment.
ek_str_slice 在 clamp 后没有处理 end < start 的情况;此时 (end - start) 为负数,强转为 uint32_t 会变成超大值,导致巨量分配/越界读取。建议在计算 new_len 前显式处理 end <= start(返回空串或交换 start/end)。
| if (start == end) return ek_str_create(""); | |
| if (end <= start) return ek_str_create(""); |
| { | ||
| ek_assert_tiny(s != NULL); | ||
|
|
||
| s->len = 0; |
There was a problem hiding this comment.
ek_str_clear 只把 len 置 0,但如果 buf 已分配,ek_str_get_cstring 仍会返回旧内容(因为未写入 buf[0] = '\0')。建议 clear 时同步写入终止符,确保 C 字符串语义正确。
| s->len = 0; | |
| s->len = 0; | |
| if (s->buf != NULL) | |
| { | |
| s->buf[0] = '\0'; | |
| } |
| EK_LOG_INFO("cat test"); | ||
| EK_LOG_INFO("make a new string:%s", n1netynine99); | ||
| ek_str_t *s1 = ek_str_create(n1netynine99); | ||
| EK_LOG_INFO("string:%s", ek_str_get_cstring(s)); |
There was a problem hiding this comment.
这里刚创建了 s1 = ek_str_create(n1netynine99);,但日志打印的是 ek_str_get_cstring(s) 而不是 s1,会导致测试输出误导。建议改为打印 s1。
| EK_LOG_INFO("string:%s", ek_str_get_cstring(s)); | |
| EK_LOG_INFO("string:%s", ek_str_get_cstring(s1)); |
| // 如果传入追加内容为空,并且字符长度也为空 | ||
| // 什么也不做 | ||
| if (str == NULL && len == 0) return true; | ||
|
|
||
| ek_assert_tiny(str != NULL); | ||
| ek_assert_tiny(len != 0); |
There was a problem hiding this comment.
ek_str_append_len 对 len == 0 做了断言(即使 str != NULL),会导致 ek_str_append(s, "") / ek_str_create("") 直接触发断言;同时 ek_str_slice 在 start == end 时调用 ek_str_create("") 也会因此崩溃。建议把 len == 0(无论 str 是否为 NULL)当作 no-op 并直接返回 true。
| // 如果传入追加内容为空,并且字符长度也为空 | |
| // 什么也不做 | |
| if (str == NULL && len == 0) return true; | |
| ek_assert_tiny(str != NULL); | |
| ek_assert_tiny(len != 0); | |
| // 长度为 0 时,无论 str 是否为 NULL,都视为 no-op | |
| if (len == 0) return true; | |
| // 只有在真正需要读取数据时才要求 str 非空 | |
| ek_assert_tiny(str != NULL); |
| if (len < 0) return false; | ||
|
|
||
| if (_ek_str_ensure_cap(s, s->len + len) == false) return false; | ||
|
|
||
| va_start(args, fmt); | ||
| // +1 给 \0 | ||
| lwvsnprintf(s->buf + s->len, len + 1, fmt, args); | ||
| va_end(args); |
There was a problem hiding this comment.
ek_str_append_fmt 里 lwvsnprintf 会写入 len + 1(包含 \0),但 _ek_str_ensure_cap 只按 s->len + len 确保容量,可能导致末尾 \0 写越界。建议确保容量至少为 s->len + len + 1。
No description provided.