Кто-нибудь может порекомендовать способ написать функцию, которая подсчитывает количество полей в структуре? т.е. псевдокод - для поля в структуре - PullRequest
0 голосов
/ 20 мая 2019

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

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

Я предполагаю, что у меня проблема XY (согласно предложениям). Так или иначе, причина, по которой я бы использовал этот типФункция заключается в том, что я хочу отправить структуры через сокет и избежать всего процесса сериализации, поэтому я пытаюсь сделать это путем добавления разделителей к элементам поля структуры.Например:

0x001 -> hdrdata -> 0x003 -> hdrdata -> 0x017 -> 0x002 -> bodydata -> 0x003 -> bodydata -> 0x003 -> bodydata-> 0x004

Как вы можете видеть, это может быть 1 bodydata или может быть 10 bodydata и т. Д. Единственное, что я могу быстро подумать, это добавить члена в мои структуры, который бы информировал мой заголовок о том, какбудет проходить много передач «bodydata», поэтому клиент знает, сколько ожидают 0x003.

Или (и я не прошу ответа на этот вопрос, но не стесняйтесь, если вы так склонны) может кто-нибудь порекомендоватьлучший дизайн протокола для отправки структур через сокет в Unix?Большая часть этого проекта предназначена для моего собственного обучения, поэтому я не заинтересован в использовании уже готового решения для библиотеки / пакета, иначе я бы просто написал это на другом языке.

1 Ответ

1 голос
/ 21 мая 2019

Это очень, очень уродливо, но я могу думать только о X-Macro:

#include <stdio.h>

#define MEMBERS \
    X(char a)   \
    X(float b)  \
    X(double c)

struct T {
#define X(x) x;
    MEMBERS
#undef X
};

int main(void)
{
    size_t n = 0
#define X(x) +1
    MEMBERS
#undef X
    ;

    printf("%zu members\n", n);
    return 0;
}

Это расширяется до:

#include <stdio.h>

struct T {
    char a;
    float b;
    double c;
};

int main(void)
{
    size_t n = 0+1+1+1;

    printf("%zu members\n", n);
    return 0;
}

Как указано @ HAL9000 в комментариях, вы можете одновременно сгенерировать и (struct, и счетчик) следующим образом:

#include <stdio.h>

#define GENERATE_STRUCT(s) s;
#define GENERATE_SCOUNT(s) +1

#define set_struct(name)            \
struct name {                       \
    name##_members(GENERATE_STRUCT) \
};                                  \
                                    \
size_t name##_count(void)           \
{                                   \
    return 0                        \
    name##_members(GENERATE_SCOUNT) \
    ;                               \
}

#define foo_members(X)  \
    X(char a)           \
    X(float b)          \
    X(double c)

set_struct(foo)

int main(void)
{
    printf("%zu members\n", foo_count());
    return 0;
}

В этом случае расширяется до:

#include <stdio.h>

struct foo {
    char a;
    float b;
    double c;
};

size_t foo_count(void)
{
    return 0+1+1+1;
}

int main(void)
{
    printf("%zu members\n", foo_count());
    return 0;
}

Наконец, другая реализация, предоставленная @Lundin, использует enum вместо переменной:

#include <stdio.h>

#define MEMBERS       \
/*    type    name */ \
    X(char,   a)      \
    X(float,  b)      \
    X(double, c)      \

struct T {
  #define X(type, name) type name;
    MEMBERS
  #undef X
};

enum
{
  #define X(type, name) dummy_##name,
    MEMBERS
  #undef X
  MEMBER_COUNT
};

int main(void)
{
    printf("%d members\n", MEMBER_COUNT);
    return 0;
}

Расширяется до:

#include <stdio.h>

struct T {
    char a;
    float b;
    double c;
};

enum {
    dummy_a,
    dummy_b,
    dummy_c,
    MEMBER_COUNT
};

int main(void)
{
    printf("%d members\n", MEMBER_COUNT);
    return 0;
}
...