Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there C macro for member methods?

Functions can be coupled to their referring structure by using function pointers.

struct string
{
    char *value;
    size_t (*size)(struct string *);
};

size_t size(struct string *this)
{
    size_t i;
for(i = 0; this->value[i] != '\0'; ++i);
return i;
}

struct string *construct()
{
    string this = (string)malloc(sizeof(struct string));
    this.size = &size;
    // ...
}

int main()
{
    struct string *s = construct();
    // ...
    s->size(s); // explicitly pass self reference
}

But I would like to get rid of passing the this pointer manually. I know that this is done implicitly in C++ when you call a method of an object. Is there a way to create a macro for this in C that works for all methods and signatures?

For example, I could think of a syntax like this.

s=>size(); // implicitly pass self reference

Please note that this is just for learning purpose. I know that it is better to just use C++ if that is possible and you'd like to use class coupling. But I'm interested of how it could be done in C.

like image 427
danijar Avatar asked Jan 31 '14 21:01

danijar


2 Answers

Yes, it is possible if you're able to use the variadic macros feature:

// ...

#define CALL_METHOD(x, y, ...) x->y(x, ##__VA_ARGS__)

struct string
{
    char *value;
    size_t (*size)(struct string *);
    int (*compare)(struct string *, struct string *);
    int (*set_value)(struct string *, const char *);
};

// ...

int main()
{
    // ...

    CALL_METHOD(s1, set_value, "foo");
    CALL_METHOD(s2, set_value, "bar");

    printf("s1->size(s1) = %zu;\n", s1->size(s1));
    printf("CALL_METHOD(s1, size) = %zu;\n", CALL_METHOD(s1, size));
    printf("s1->compare(s1, s2) = %d;\n", s1->compare(s1, s2));
    printf("CALL_METHOD(s1, compare, s2) = %d;\n", CALL_METHOD(s1, compare, s2));

    // ...
}
like image 60
Fernando Silveira Avatar answered Sep 18 '22 11:09

Fernando Silveira


You can think as s->size() syntax.

If you think in multiple scopes of a function this is possible.

To GCC

#include <stdio.h>
#include <stdlib.h>

typedef struct {
        const char *value;
        size_t (*size)();
        void (*destroy)();
} string;

#define STRING(A)                                               \
        string *A = (string *) malloc(sizeof(string));          \
        A->value = "";                                          \
        {                                                       \
                size_t size() {                                 \
                        size_t i;                               \
                                                                \
                        for(i = 0; A->value[i] != '\0'; ++i);   \
                        return i;                               \
                }                                               \
                                                                \
                void destroy() {                                \
                        free(A);                                \
                }                                               \
                                                                \
                A->size = &size;                                \
                A->destroy = &destroy;                          \
        }

int main() {
        printf("\n=== s1 ===\n");
        STRING(s1);
        printf("Size: %ld\n", s1->size());
        s1->value = "FOOO";
        printf("%s\n", s1->value);
        printf("Size: %ld\n", s1->size());

        printf("\n=== s2 ===\n");
        STRING(s2);
        printf("Size: %ld\n", s2->size());
        s2->value = "BAZ";
        printf("%s\n", s2->value);
        printf("Size: %ld\n", s2->size());

        printf("\n=== s1 ===\n");
        s1->value="A";
        printf("Size: %ld\n", s1->size());
        printf("%s\n", s1->value);

        printf("\n=== s2 ===\n");
        s2->value="ZZ";
        printf("Size: %ld\n", s2->size());
        printf("%s\n", s2->value);

        s1->destroy();
        s2->destroy();

        return 0;
}

To standart C

#include <stdio.h>
#include <stdlib.h>

#define STRING(A)                                               \
        string *A = (string *) malloc(sizeof(string));          \
        A->value = "";                                          \
        A->size = &size;                                        \
        A->destroy = &destroy;

#define USE(A)                                                  \
        s = A;

typedef struct {
        const char *value;
        size_t (*size)();
        void (*destroy)();
} string;

size_t size();
void destroy();

string *s;

size_t size() {
        size_t i;

        for(i = 0; s->value[i] != '\0'; ++i);
        return i;
}

void destroy() {
        free(s);
}

int main() {
        printf("\n=== s1 ===\n");
        STRING(s1);
        USE(s1);
        printf("Size: %ld\n", s1->size());
        s1->value = "FOOO";
        printf("%s\n", s1->value);
        printf("Size: %ld\n", s1->size());

        printf("\n=== s2 ===\n");
        STRING(s2);
        USE(s2);
        printf("Size: %ld\n", s2->size());
        s2->value = "BAZ";
        printf("%s\n", s2->value);
        printf("Size: %ld\n", s2->size());

        USE(s1);
        printf("\n=== s1 ===\n");
        s1->value="A";
        printf("Size: %ld\n", s1->size());
        printf("%s\n", s1->value);

        USE(s2);
        printf("\n=== s2 ===\n");
        s2->value="ZZ";
        printf("Size: %ld\n", s2->size());
        printf("%s\n", s2->value);

        USE(s1);
        s1->destroy();

        USE(s2);
        s2->destroy();

        return 0;
}
like image 36
TheOliverDenis Avatar answered Sep 16 '22 11:09

TheOliverDenis