Повторное использование логики функций между строкой char и строкой wchar_t без явного копирования строки?
Я пишу структуру данных в 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
в зависимости от значения которого он будет приводить строку, переданную ему как void *
либо const char *
или же const wchar_t *
но учитывая, что C статически типизирован, мне пришлось бы в значительной степени дублировать логику с s
приведение к его соответствующему типу, который разрушил бы идею, которую я собираюсь использовать для "единственного экземпляра логики".
Итак, в конечном итоге, вопрос в том, могу ли я предоставить логику программы только один раз и передать обертки const char *
а также const wchar_t *
соответственно без создания временного wchar_t *
в функции для обработки const char *
?
1 ответ
Я не знаю ваших жестких требований, но wchar_t
из-за этой проблемы трудно работать именно с ним; слишком сложно связываться с существующим кодом, который использует char
,
Все кодовые базы, с которыми я работал, в конечном итоге были перенесены в UTF-8, что устраняет необходимость хранить строки другого типа. UTF-8 работает со стандартом strcpy
/strlen
тип функций манипуляции со строками и полностью подкованный в Юникоде. Единственная проблема заключается в том, что вам нужно будет преобразовать его в UTF-16 для вызова API-интерфейсов Windows Unicode. (OS X может использовать UTF-8 напрямую.) Вы не упомянули платформу, поэтому я не знаю, будет ли это проблемой для вас. В нашем случае мы только что написали обертки Win32, которые принимали строки UTF-8.
Вы можете использовать C++? Если это так, и фактический тип wchar_t
важно (а не поддержка Unicode), вы можете шаблонизировать функции, а затем создавать их с помощью std::wstring
или же std::string
в зависимости от ширины строки. Вы также можете написать их на основе char
а также wchar_t
если вы храбры, но вам нужно написать специальные функции-оболочки для обработки основных операций, таких как strcpy
против wcscpy
и так в итоге получается больше работы в целом.
В простом С я не думаю, что есть серебряная пуля вообще. Есть отвратительные ответы, но я не могу рекомендовать их с открытым лицом.