char字符串和wchar_t字符串之间的函数逻辑重用没有显式字符串复制?

时间:2014-12-16 20:39:29

标签: c string code-reuse wchar-t memory-optimization

我在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中的逻辑。

但是,由于charwchar_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 *强制转换为相应类型的逻辑重复,这会破坏我想要“单一逻辑实例”。

最终,问题是,我是否可以只提供一次程序逻辑并分别传递包装器sconst char *,而不在函数中创建临时const wchar_t *来处理{{ 1}}?

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::wstringstd::string对它们进行实例化。如果你很勇敢,你也可以把它们写成charwchar_t,但是你需要编写特殊的包装函数来处理strcpy与{{1}等基本操作到目前为止它最终会成为更多的工作。

在简单的C中,我认为根本没有银弹。有令人讨厌的答案,但没有一个我可以直接推荐。