Повторное использование логики функций между строкой 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 и так в итоге получается больше работы в целом.

В простом С я не думаю, что есть серебряная пуля вообще. Есть отвратительные ответы, но я не могу рекомендовать их с открытым лицом.

Другие вопросы по тегам