Как создать свойства производной структуры в C - PullRequest
0 голосов
/ 02 марта 2019

В Python возможно создать производное свойство из класса, используя декоратор @property, например

class State():
    def __init__(self, fav_num_monday, fav_num_not_monday, is_monday):
        self.fav_num_monday = fav_num_monday
        self.fav_num_not_monday = fav_num_not_monday
        self.is_monday = is_monday

    @property
    def fav_num(self):
        return self.is_monday * self.fav_num_monday + \
            (1 - self.is_monday) * self.fav_num_not_monday

state = State(12, 5, 0)
print("Current favourite number: %d" % state.fav_num)

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

  1. Просто выписывая все выражение каждый раз.Плюсы: нет неожиданных последствий, нет кода / скорость наказания.Минусы: Гадкий код, написание которого занимает много времени.
  2. Использование функции get.Плюсы: код легче читать.Минусы: неэффективный код (медленнее, чем 1).
  3. Определение макроса.Плюсы: нет кода / скорость штрафа.Код быстро написать.Минусы: Потенциальные последствия позже, код не так легко следовать.

Пример программы ниже

#include <stdio.h>
#include <string.h>

#define state_fav_num  state.is_monday * state.fav_num_monday + (1 - state.is_monday) * state.fav_num_not_monday

struct State {
    int fav_num_monday;
    int fav_num_not_monday;
    int is_monday;
};

int get_state(struct State *state, char *property) {
    // Returns value of the property in state. 
    // Allows us to create derived properties also.
    if (!strncmp(property, "fav_num_monday", 14)) {
        return state->fav_num_monday;
    } else if (!strncmp(property, "fav_num_not_monday", 18)) {
        return state->fav_num_not_monday;
    } else if (!strncmp(property, "is_monday", 9)) {
        return state->is_monday;
    } else if (!strncmp(property, "fav_num", 7)) {
        return state->is_monday * state->fav_num_monday +
            (1 - state->is_monday) * state->fav_num_not_monday;
    }
}

int main() {
    // Set the state.
    struct State state;
    state.fav_num_monday = 12;
    state.fav_num_not_monday = 5;
    state.is_monday = 1;

    // Print favourite number in different ways.
    printf("\n1) Current favourite number is %d.",
        state.is_monday * state.fav_num_monday +
        (1 - state.is_monday) * state.fav_num_not_monday);

    printf("\n2) Current favourite number is %d.",
        get_state(&state, "fav_num"));

    printf("\n3) Current favourite number is %d.",
        state_fav_num);

    printf("\n");

    return 0;
}

1 Ответ

0 голосов
/ 02 марта 2019

Вы можете получить лучшее из обоих миров (функция и макрос) для удобочитаемости и производительности, с функцией static inline.

Обычно вы не будете использовать это, но если вы знаете, что компилятор собираетсячтобы оптимизировать его код, тогда можно использовать его.Обычное правило, которое я использую, состоит из 3 или менее строк кода, и функция должна требовать дополнительной производительности.

При этом ваше get_state не соответствует (моим) требованиям для функции static inline,но если вы хотите, чтобы функция получала только fav_num, это имело бы смысл:

struct State {
    int     fav_num_monday;
    int     fav_num_not_monday;
    bool    is_monday;
};


static inline   int get_fav_num(const struct State *state)
{

    if (state->is_monday)
        return  state->fav_num_monday;
    else
        return  state->fav_num_not_monday;
}


int main(void)
{
    struct State state;
    int fav_num;

    state   = (struct State){
        .fav_num_monday     = 12;
        .fav_num_not_monday = 5;
        .is_monday          = 1;
    };

    // Print favourite number in different ways.
    printf("\n");
    if (state.is_monday)
        fav_num = state->fav_num_monday;
    else
        fav_num = state->fav_num_not_monday;
    printf("1) Current favourite number is %d.\n", fav_num);

    fav_num = get_fav_num(&state);
    printf("4) Current favourite number is %d.\n", fav_num);

    return 0;
}

Отказ от ответственности: для этого кода требуется C99 или более поздняя версия.

Хотя здесь все вместе,struct State {...}; и функция static inline будут обычно помещаться в файл заголовка .h.

Кроме того, я бы улучшил вашу функцию get_state следующим образом:

enum Properties {
    FAV_NUM_MONDAY,
    FAV_NUM_NOT_MONDAY,
    IS_MONDAY,
    FAV_NUM
};

int get_state(const struct State *state, int property)
{

    switch (property) {
    case FAV_NUM_MONDAY:
        return  state->fav_num_monday;
    case FAV_NUM_NOT_MONDAY:
        return  state->fav_num_not_monday;
    case IS_MONDAY:
        return  state->is_monday;
    case FAV_NUM:
        return  get_fav_num(state);
    default:
        return -1;  /* Error */
    }
}

Эта функция будет обычной extern функцией и будет помещаться в файл .c, хотя enum Properties должен идти в заголовочном файле, чтобы ее мог использовать пользователь функции.

Редактировать: Добавить высокопроизводительную версию с использованием массива

state.h

#include <stdint.h>

enum    State_Properties {
    FAV_NUM_MONDAY,
    FAV_NUM_NOT_MONDAY,
    IS_MONDAY,
    STATE_PROPERTIES
};


static inline
uint_fast8_t get_fav_num(const uint_fast8_t *restrict (state[STATE_PROPERTIES]))
{

    if ((*state)[IS_MONDAY])
        return  (*state)[FAV_NUM_MONDAY];
    else
        return  (*state)[FAV_NUM_NOT_MONDAY];
}

main.c

#include <inttypes.h>

#include "state.h"

int main(void)
{
    uint_fast8_t    state[STATE_PROPERTIES];
    uint_fast8_t    fav_num;
    uint_fast8_t    fav_num_monday;

    state   = (uint_fast8_t [STATE_PROPERTIES]){
        [FAV_NUM_MONDAY]        = 12;
        [FAV_NUM_NOT_MONDAY]    = 5;
        [IS_MONDAY]             = true;
    };

    // Print favourite number in different ways.
    fav_num = get_fav_num(&state);
    printf("5) Current favourite number is %"PRIuFAST8".\n", fav_num);

    // Example of how to retrieve any property:
    fav_num_monday  = state[FAV_NUM_MONDAY];
}

Конечно, вы можете изменить тип на кого угодноЯ использовал uint_fast8_t, потому что ваши данные могут поместиться там, и это самый быстрый тип в любой системе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...