2014-12-31 2 views
0

Представьте себе, что у вас есть такие: СтруктурыКастинг указатель на структуру, чтобы указатель на структуру с сопзЬ членом

struct nix_codec { 
    nix_uint8 state; 
    nix_uint8 mode; 
    nix_uint8 flags; 
    nix_size offset; 
    nix_uint32 codepage; 
    nix_utf8 const *const *aliases; 
    void (*delete)(
     struct nix_codec *codec, 
     struct nix_error *error 
    ); 
    struct nix_codec* (*clone)(
     struct nix_codec const *codec, 
     nix_int8 mode, 
     struct nix_error *error 
    ); 
    nix_size (*decode)(
     struct nix_codec *codec, 
     nix_byte const *bdata, 
     nix_size bsize, 
     nix_rune *udata, 
     nix_size usize, 
     struct nix_error *error 
    ); 
    nix_size (*encode)(
     struct nix_codec *codec, 
     nix_rune const *udata, 
     nix_size usize, 
     nix_byte *bdata, 
     nix_size bsize, 
     struct nix_error *error 
    ); 
}; 

typedef struct { 
    nix_uint8 const state; 
    nix_uint8 const mode; 
    nix_uint8 const flags; 
    nix_size const offset; 
    nix_uint32 const codepage; 
    nix_utf8 const *const *const aliases; 
} nix_codec; 

Один имеет также несколько функций, которые используются для создания nix_codec* экземпляров, например, для UTF-8 кодека будет выглядеть следующим образом:

static nix_size self_decode 
(
    struct nix_codec *codec, 
    nix_byte const *bdata, 
    nix_size bsize, 
    nix_rune *udata, 
    nix_size usize, 
    struct nix_error *error 
) 
{ /* UTF-8 decode function, too long to post here */} 

static nix_utf8 const *const aliases[] = { 
    "UTF-8", 
    "UTF8", 
    "CP65001", 
    NULL, 
}; 

nix_codec *nix_codec_utf8 
(
    nix_int8 mode, 
    struct nix_error *error 
) 
{ 
    struct nix_codec *codec = NULL; 

    if ((mode != NIX_CODEC_STRICT) && (mode != NIX_CODEC_ESCAPE) 
    && (mode != NIX_CODEC_REPLACE) && (mode != NIX_CODEC_IGNORE)) { 
     return NULL; 
    } 
    codec = calloc(1, sizeof(struct nix_codec)); 
    if (codec == NULL) { 
     return NULL; 
    } 
    codec->mode = mode; 
    codec->codepage = 65001; 
    codec->aliases = aliases; 
    codec->decode = &self_decode; 
    codec->encode = &self_encode; 
    codec->flags = (NIX_CODEC_COMPATIBLE | NIX_CODEC_MULTIBYTE | NIX_CODEC_ABSOLUTE); 
    return (nix_codec*)codec; 
} 

Функция для устаревших однобайтных кодировок на основе таких структур:

struct nix_sbmap { 
    nix_uint8 byte; 
    nix_rune rune; 
}; 

struct nix_sbcodec { 
    struct nix_codec base; 
    struct nix_sbmap const *entries; 
    nix_size count; 
}; 

Обратите внимание, что struct nix_sbcodec и struct nix_sbmap объявлены в исходных файлах , а не в заголовках, поэтому нет необходимости использовать шаблон variant. Соответствующая функция, например. nix_codec_koi8r(), назначает struct nix_sbcodec, устанавливает base, entries и count членов, а затем бросает его на nix_codec и возвращает его. Каждые фактические encode() и decode() вызовов выполняется с помощью этой общественной функции:

nix_size nix_codec_decode 
(
    nix_codec *codec, 
    nix_byte const *bdata, 
    nix_size bsize, 
    nix_rune *udata, 
    nix_size usize, 
    struct nix_error *error 
) 
{ 
    nix_size result = 0; 
    struct nix_codec *self = (struct nix_codec*)codec; 

    return self->decode(self, bdata, bsize, udata, usize, error); 
} 

Обратите внимание, что state, mode, flags и offset членов могут быть интересными для любого, используя любой кодек (большая часть из них находится в кодеке функции создателя , offset изменяется после вызовов на encode() и decode() функций и представляет собой количество символов байт/Unicode, которые были успешно обработаны, прежде чем функция завершается. Каждый кодек имеет свою собственную encode() и decode() функции, как вы видите.

Теперь вопрос: этот трюк правильный и гарантированно работает по стандарту C?

Заранее благодарен!

+2

В чем вопрос? – IdeaHat

+0

'класс'? в 'c'? –

+0

Это C не C++ правильно? Зачем ты это делаешь? Это откровенно несчастный случай, ожидающий своего служения. Что вы ожидаете от компилятора, если вы присваиваете один «my_object» другому? (Подсказка: 'memcpy (b, a, sizeof (my_object)') –

ответ

0

Надежный способ иметь дело с вариантами типов в C, например, как я думаю, вы пытаетесь использовать union. Например:

typedef struct { 
    uint8_t x; 
    uint16_t y; 
} obj_a; 

typedef struct { 
    char *p; 
    char buf[42]; 
} obj_b; 

typedef struct obj_base_s { 
    int (*internal_func)(struct obj_base_s *, int); 
    union { 
     obj_a a; 
     obj_b b; 
    } u; 
} obj_base; 

Все функции создателя/деструктор будет возвращать или использовать obj_base. Функции, которые используют член в union может получить доступ к их битам непосредственно еще сделать что-то вроде этого:

void handle_obja(obj_base *bp) 
{ 
    obj_a *oap = &bp->u.a; 
    oap->x = 23; 
    oap->y = 19; 
    ... 
} 

С не C++, если вы хотите хорошие классы, наследование, перегружать и все, что материал, а затем использовать C++ , Это основная причина, по которой C++ был изобретен. C не выполняет «классы». C - язык более низкого уровня.

+0

Шаблон «Вариант» здесь не применяется.Я говорю о наследовании, но может быть много структур, которые наследуют 'my_object', и я не вижу никаких преимуществ поместить каждый' вариант' в объявление 'my_object'. – ghostmansd

+0

См. Обновленный пост. Надеюсь, что это прояснит ситуацию. – ghostmansd

+0

C не имеет понятия наследования. В конечном счете, чтобы имитировать наследование C++, у вас либо есть большая структура, которую вы, программист, разделите на куски, относящиеся к различным наборам функций. Или вы используете разные структуры и (так или иначе) передаете указатели void на эти структуры. Но имитировать C++ - это то, что вы делаете. Если вы можете найти рабочую копию 'cfront', вам может быть интересно ее выход. Это было то, как C++ первоначально был предварительно обработан в C перед компиляцией. IIRC он просто создал одну большую структуру для набора классов. –

0

Обратите внимание, что state, mode, flags и offset члены могут быть интересно кому-либо с помощью любого кодека (...

Теперь вопрос: это трюк правильно и гарантированно работать на C стандарта?

Однако полезно это может быть и как бы часто он может работать, этот трюк (доступ членов struct nix_codec объекта, указатель на объект по-разному определяется nix_codec объекта) опасен, если не утверждать, что соответствующие члены обоихов типы структуры имеют соответственно одинаковое смещение в структурах; это не гарантируется для независимо определенных типов структуры; такая гарантия существует только в объединении структур - смотрите раздел Языка/Выражение/Postfix операторы/Структуры и члены профсоюза/пункт 6:

Особой гарантия делается для того, чтобы упростить использование объединений: если объединение содержит несколько структур, которые имеют общую начальную последовательность (см. ниже), и если объект объединения в настоящее время содержит одну из этих структур, разрешается проверять общую начальную часть любого из их везде, где декларация завершен тип соединения . Две структуры разделяют общую начальную последовательность , если соответствующие члены имеют совместимые типы (и для битовых полей одинаковой ширины) для последовательности из одного или нескольких начальных элементов .

Смежные вопросы