我在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)
)增加五倍,如果存在大量的内存,则可能会堆叠将用冗长的命令实例化。
我想知道我可以做一些事情,比如创建一个包含逻辑的第三个函数,然后传递一个size_t
,具体取决于它将传递给它的字符串作为{{{1}传递给它的值。 1}}要void *
或const char *
,但鉴于C是静态类型的,我必须将const wchar_t *
强制转换为相应类型的逻辑重复,这会破坏我想要“单一逻辑实例”。
最终,问题是,我是否可以只提供一次程序逻辑并分别传递包装器s
和const char *
,而不在函数中创建临时const wchar_t *
来处理{{ 1}}?
答案 0 :(得分:3)
我不知道你的硬性要求,但wchar_t
因为这个问题而往往难以合作。与使用char
的现有代码进行网格划分太难了。
我使用的所有代码库最终都迁移到UTF-8,这消除了以不同类型存储字符串的必要性。 UTF-8使用标准的strcpy
/ strlen
类型的字符串操作函数,并且完全符合Unicode。唯一的挑战是您需要将其转换为UTF-16以调用Windows Unicode API。 (OS X可以直接使用UTF-8。)你没有提到平台,所以我不知道这对你来说是不是一个问题。在我们的例子中,我们只编写了带有UTF-8字符串的Win32包装器。
你能用C ++吗?如果是这样,并且实际类型wchar_t
很重要(而不是Unicode支持),您可以对这些函数进行模板化,然后根据字符串宽度使用std::wstring
或std::string
对它们进行实例化。如果你很勇敢,你也可以把它们写成char
和wchar_t
,但是你需要编写特殊的包装函数来处理strcpy
与{{1}等基本操作到目前为止它最终会成为更多的工作。
在简单的C中,我认为根本没有银弹。有令人讨厌的答案,但没有一个我可以直接推荐。