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.
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));
// ...
}
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With