TransWikia.com

Замена многих вызовов функции на более элегантное решение (цикл)

Stack Overflow на русском Asked by user206435 on November 27, 2021

Допустим у меня есть функция для парсинга Url, и для того что бы распарсить каждую часть, а так же помимо этого добавить флаг присутствия той или иной части, вызывается одна функция, в которую передается enum (флаги), и на данный момент это выглядит примерно так:

enum libkodik_url_flag_e {
    libkodik_url_flag_scheme    = 1u << 0u,
    libkodik_url_flag_user      = 1u << 1u,
    libkodik_url_flag_password  = 1u << 2u,
    libkodik_url_flag_host      = 1u << 3u,
    libkodik_url_flag_port      = 1u << 4u,
    libkodik_url_flag_path      = 1u << 5u,
    libkodik_url_flag_query     = 1u << 6u,
    libkodik_url_flag_fragment  = 1u << 7u,
    libkodik_url_flag_max       = 1u << 8u
};

KODIK_CORE_API libkodik_url_t *
libkodik_url_parse(char const *url, int *error) {
    libkodik_url_t* p_data = NULL;

    ...

    uint32_t i_parts_count = 0;

    p_data = libkodik_url_alloc();
    p_data->psz_raw = strdup(url);
    char *psz_part = libkodik_url_parse_part(url, libkodik_url_flag_scheme);

    if(NULL != psz_part) {
        i_parts_count++;
        p_data->i_flags |= libkodik_url_flag_scheme;
        p_data->p_url_parts = realloc(p_data->p_url_parts,
                                      i_parts_count * sizeof(libkodik_url_part_t));
        libkodik_url_write_part(&p_data->p_url_parts[i_parts_count],
                                psz_part, libkodik_url_flag_scheme);
        ...
    } else {
        psz_part = url;
    }

    ...

    *error = 0;
    return p_data;
}

Но я хотел бы сделать это дело циклом, т.е. данные там устанавливаются одинаково, но я не понимаю как мне перебрать enum в цикле, т.к. он является значением флагов…

Повторяющаяся часть кода:

char *psz_part = libkodik_url_parse_part(url, libkodik_url_flag_scheme);

if(NULL != psz_part) {
    i_parts_count++;
    p_data->i_flags |= libkodik_url_flag_scheme;
    p_data->p_url_parts = realloc(p_data->p_url_parts,
                                  i_parts_count * sizeof(libkodik_url_part_t));
    libkodik_url_write_part(&p_data->p_url_parts[i_parts_count],
                            psz_part, libkodik_url_flag_scheme);
    ...
} else {
    psz_part = url;
}

P.S. libkodik_url_flag_max не учитывается.

One Answer

Так как флаги у вас идут подряд, можно перебирать циклом просто сдвигая нужный бит. Флаг libkodik_url_flag_scheme = 1u << 0u имеет значение 000000001b. А флаг libkodik_url_flag_user = 1u << 1u равен 000000010b. И наконец последний libkodik_url_flag_max = 1u << 8u равен 100000000b.
Перебираем циклом начиная с первого флага до последнего так :

enum libkodik_url_flag_e  flag  ;
for ( flag = libkodik_url_flag_scheme ;
  flag != libkodik_url_flag_max ; flag <<= 1 )
  /* нужная работа со значением флага flag */;

На следующий флаг переходим с помощью битового сдвига <<= 1. И если был флаг flag = 000010000b. То с помощью flag <<= 1 он станет равным 000100000b.

Answered by AlexGlebe on November 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP