【问题标题】:Function logic reuse between char string and wchar_t string without explicit string copying?char字符串和wchar_t字符串之间的函数逻辑重用没有显式字符串复制?
【发布时间】: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

但是,由于charwchar_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


【解决方案1】:

我不知道您的硬性要求,但 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 编写它们,但是你需要编写特殊的包装函数来处理strcpywcscpy 这样的基本操作,所以它最终会更多到目前为止总体工作。

在普通的 C 语言中,我认为根本没有灵丹妙药。有一些令人讨厌的答案,但我不能直截了当地推荐。

【讨论】:

  • 我喜欢纯 UTF-8 的想法,但 C 使用 wchar_t 存储 UTF-8 的标准做法不是吗?在这种情况下,我将如何重构我现有的代码?在平台方面,符合 POSIX 的操作系统集是我的主要目标; Windows 移植更多的是事后的想法。
  • UTF-8 始终存储在 8 位 char 中,从不在 wchar_t 中。如果您的目标是 POSIX,那么您真的根本不需要 wchar_t。 POSIX API 不使用它。
  • 啊,好吧。所以我可以完全取消widechar方法吗?
  • 我支持对所有内容使用 UTF-8 并仅在需要调用外部代码时转换为其他格式的建议。
  • 在大量使用 WinAPI 的代码中,调用函数来获取 utf-16 字符串、转换为 utf-8、传递给另一个函数、转换回 utf-16 并调用另一个函数似乎很奇怪WinAPI 函数。所以我的 WinAPI 代码往往是两者的混合,这很烦人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 1970-01-01
  • 2018-11-12
  • 2012-07-11
  • 1970-01-01
  • 2011-02-25
相关资源
最近更新 更多