【发布时间】:2015-02-15 06:56:56
【问题描述】:
我正在用 C 语言编写一个数据结构来存储命令;以下是我不满意的来源:
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include "dbg.h"
#include "commandtree.h"
struct BranchList
{
CommandTree *tree;
BranchList *next;
};
struct CommandTree
{
wchar_t id; // wchar support actually has no memory cost due to the
bool term; // padding that would otherwise exist, and may in fact be
BranchList *list; // marginally faster to access due to its alignable size.
};
static inline BranchList *BranchList_create(void)
{
return calloc(1, sizeof(BranchList));
}
inline CommandTree *CommandTree_create(void)
{
return calloc(1, sizeof(CommandTree));
}
int CommandTree_putnw(CommandTree *t, const wchar_t *s, size_t n)
{
for(BranchList **p = &t->list;;)
{
if(!*p)
{
*p = BranchList_create();
if(errno == ENOMEM) return 1;
(*p)->tree = CommandTree_create();
if(errno == ENOMEM) return 1;
(*p)->tree->id = *s;
}
else if(*s != (*p)->tree->id)
{
p = &(*p)->next;
continue;
}
if(n == 1)
{
(*p)->tree->term = 1;
return 0;
}
p = &(*p)->tree->list;
s++;
n--;
}
}
int CommandTree_putn(CommandTree *t, const char *s, size_t n)
{
wchar_t *passto = malloc(n * sizeof(wchar_t));
mbstowcs(passto, s, n);
int ret = CommandTree_putnw(t, passto, n);
free(passto);
return ret;
}
这很好用,但我对我的树支持wchar_t这一事实的处理方式相当不满意。当我意识到 CommandTree 的填充会使任何小于 7 字节的数据类型花费同样多的内存时,我决定添加这个,但为了不重复代码,我有 CommandTree_putn 重用 wchar_t 中的逻辑-支持CommandTree_putnw。
但是,由于char和wchar_t的大小不同,我不能只传递数组;我必须使用mbstowcs 进行转换并将临时wchar_t * 传递给CommandTree_putnw。这是次优的,因为 CommandTree_putn 将看到最多的使用量,并且这将存储字符串的内存使用量(sizeof (char) 到 sizeof (char) + sizeof (wchar_t))增加五倍,如果其中很多将被实例化为 longish,则可能会堆叠命令。
我想知道我可以做一些事情,比如创建一个包含逻辑的第三个函数,并传递一个size_t,这取决于它将作为void *传递给它的字符串的值转换为const char * 或 const wchar_t * 但鉴于 C 是静态类型的,我必须将 s 强制转换为其各自类型的逻辑几乎重复,这会破坏我想要的“单实例”的想法逻辑”。
所以最终的问题是,我是否可以只提供一次程序逻辑并分别传递包装器 const char * 和 const wchar_t *,而不在函数中创建临时的 wchar_t * 来处理 const char *?
【问题讨论】:
-
你应该把那一大段分成几个单独的句子,这样阅读起来更容易!
标签: c string code-reuse wchar-t memory-optimization