Compare commits

...

10 Commits

Author SHA1 Message Date
Richard Thier
fe07cf2106 licence and stuff plus minor changes 2025-04-25 21:44:24 +02:00
Richard Thier
53e4cb652f more fixes and checked clang++ build for generics 2025-04-25 03:35:27 +02:00
Richard Thier
9e642f9ed4 fixed valgrind-found bugs in generic test code, also fixed its cpp build 2025-04-25 03:32:32 +02:00
Richard Thier
6f106988b4 generic programming example added for RAII in C 2025-04-25 01:50:15 +02:00
Richard Thier
1b860723b8 added array/vektor example (missing file) 2025-04-25 01:45:51 +02:00
Richard Thier
68a51e7d7e added c++ expansion example for those interested 2025-04-25 00:06:02 +02:00
Richard Thier
91b20bc366 refactor this with self + add c++ compat 2025-04-25 00:05:39 +02:00
Richard Thier
bf5ad27064 better example - more real usecase 2025-04-24 23:08:32 +02:00
Richard Thier
476a01d6d4 fixed bugs - now handles work with gcc (see example) 2025-04-24 20:58:06 +02:00
Richard Thier
d6bb77d112 interesting debug session + make expand 2025-04-24 20:14:43 +02:00
13 changed files with 355 additions and 39 deletions

15
array.h Normal file
View File

@ -0,0 +1,15 @@
#include <stdlib.h>
#include "handle.h"
/* Generic array macro */
#define Array(T,AT) struct AT { \
size_t count; \
T *v; \
}; handle(AT) { \
if(state == HANDLE_CREAT) { \
self->count = *(size_t*) data; \
self->v = (T*) calloc(self->count, sizeof(T)); \
} else if (state == HANDLE_DESTR){ \
if(self->v) free(self->v); \
} \
}

27
array_handle_gen_test.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "array.h"
/* Prepare usage for 64 bit arrays - adds "Array_uint64" for creat */
Array(uint64_t, Array_uint64);
int main() {
size_t n = 0;
printf("Number of elements to sum: ");
scanf(" %zu", &n);
/* Create a 64 bit array of 'n' elements named 'data' */
creat(Array_uint64, data, &n);
for(int i = 0; i < data.count; ++i) {
scanf(" %zu", &n);
data.v[i] = n;
}
n = 0; for(int i = 0; i < data.count; ++i) n += data.v[i];
printf("Sum: %zu\n", n);
// RAII releases array here automagicaly!
return 0;
}

32
array_handle_test.c Normal file
View File

@ -0,0 +1,32 @@
#include <stdio.h>
#include <stdlib.h>
#include "handle.h"
struct Vektor {
int count;
int *v;
}; handle(Vektor) {
if(HANDLE_CREAT == state) {
self->count = *(int*) data;
self->v = (int*) calloc(self->count, sizeof(int));
} else if (HANDLE_DESTR == state){
if(self->v) free(self->v);
}
}
int main() {
int n;
printf("Number of elements to sum: ");
scanf(" %d", &n);
creat(Vektor, data, &n);
// printf("data.count:%d\n", data.count);
for(int i = 0; i < data.count; ++i) {
scanf(" %d", &n);
data.v[i] = n;
}
n = 0; for(int i = 0; i < data.count; ++i) n += data.v[i];
printf("Sum: %d\n", n);
return 0;
}

48
array_test.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
struct Vektor {
int count;
int *v;
};
typedef struct Vektor Vektor;
Vektor create_Vektor(int count) {
Vektor self;
self.count = count;
self.v = (int*) calloc(self.count, sizeof(int));
return self;
}
int sum_Vektor(Vektor *self) {
int s = 0;
for(int i = 0; i < self->count; ++i) {
s += self->v[i];
}
return s;
}
void delete_Vektor(Vektor *self) {
if(self->v) free(self->v);
}
int main() {
int n;
printf("Number of elements to sum: ");
scanf(" %d", &n);
Vektor data = create_Vektor(n);
// printf("vektor.count:%d\n", data.count);
for(int i = 0; i < data.count; ++i) {
scanf(" %d", &n);
data.v[i] = n;
}
// n = 0; for(int i = 0; i < data.count; ++i) n += data.v[i];
n = sum_Vektor(&data);
printf("Sum: %d\n", n);
// Need to not forget this
delete_Vektor(&data);
return 0;
}

48
bugsy.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
enum HANDLE_STATE {
HANDLE_CREAT,
HANDLE_DESTR
};
struct Array_uint64 { size_t count; uint64_t *v; };
static inline void Array_uint64_lifetime_handler(
enum HANDLE_STATE state,
struct Array_uint64 *self,
void *data) {
if(state == HANDLE_CREAT) {
self->count = *(size_t*) data;
printf("self: %zd, count: %d", self, self->count);
self->v = (uint64_t*) calloc(self->count, sizeof(uint64_t));
} else if (state == HANDLE_DESTR) {
if(self->v) free(self->v);
}
};
int main() {
// XXX: size_t n = 0;
int n; // FIXME: BUG
printf("Number of elements to sum: ");
// XXX: scanf(" %zu", &n);
scanf(" %d", &n); // FIXME: BUG
[[gnu::always_inline]] inline void data_cleanuper(struct Array_uint64 *v) {
Array_uint64_lifetime_handler(HANDLE_DESTR, v, ((void *)0) );
}
[[gnu::cleanup(data_cleanuper)]] struct Array_uint64 data;
Array_uint64_lifetime_handler(HANDLE_CREAT, & data, &n);;
for(int i = 0; i < data.count; ++i) {
scanf(" %d", &n);
data.v[i] = n;
}
n = 0; for(int i = 0; i < data.count; ++i) n += data.v[i];
printf("Sum: %d\n", n);
return 0;
}

View File

@ -6,8 +6,8 @@ void __attribute__((destructor)) calledLast();
int main() { int main() {
printf("\nI am in main"); printf("\nI am in main");
// return 0; return 0;
exit(0); // Even called on this!!! // exit(0); // Even called on this!!!
} }
void calledFirst() { void calledFirst() {

31
expanded.c Normal file
View File

@ -0,0 +1,31 @@
#include <stdio.h>
enum HANDLE_STATE {
HANDLE_CREAT,
HANDLE_DESTR
};
struct Meaning {
int a;
int b;
};
static inline void Meaning_lifetime_handler(enum HANDLE_STATE state, struct Meaning *this, void *data) {
if(state == HANDLE_CREAT) {
this->a = *(int*) data;
this->b = 2;
} else {
printf("%d\n", this->a + this->b);
}
}
int main() {
int initializer = 40;
[[gnu::always_inline]] inline void F(struct Meaning *v) { Meaning_lifetime_handler(HANDLE_DESTR, v,
((void *)0)
); } [[gnu::cleanup(F)]] struct Meaning d; Meaning_lifetime_handler(HANDLE_CREAT, & d, &initializer);;
return 0;
}

35
expanded.cpp Normal file
View File

@ -0,0 +1,35 @@
#include <stdio.h>
enum HANDLE_STATE {
HANDLE_CREAT,
HANDLE_DESTR
};
struct Vektor {
int count;
int *v;
}; struct Vektor_raiicpp; static inline void Vektor_lifetime_handler( enum HANDLE_STATE state, struct Vektor_raiicpp *self, void *data); struct Vektor_raiicpp : public Vektor { inline Vektor_raiicpp(void *data) { Vektor_lifetime_handler(HANDLE_CREAT, this, data); } inline ~Vektor_raiicpp() { Vektor_lifetime_handler(HANDLE_DESTR, this, nullptr); } } static inline void Vektor_lifetime_handler( enum HANDLE_STATE state, struct Vektor_raiicpp *self, void *data) {
if(state == HANDLE_CREAT) {
self->count = *(int*) data;
self->v = calloc(self->count, sizeof(int));
} else if (state == HANDLE_DESTR){
if(self->v) free(self->v);
}
}
int main() {
int n;
printf("Number of elements to sum: ");
scanf(" %d", &n);
Vektor_raiicpp data(&n);;
for(int i = 0; i < data.count; ++i) {
scanf(" %d", &n);
data.v[i] = n;
}
n = 0; for(int i = 0; i < data.count; ++i) n += data.v[i];
printf("Sum: %d\n", n);
return 0;
}

View File

@ -1,33 +1,69 @@
#ifndef MAG_HANDLE_H #ifndef MAG_HANDLE_H
#define MAG_HANDLE_H #define MAG_HANDLE_H
/* Simple single-header library that makes you have RAII in gcc (also works in C++ compilers) */
#ifdef __cplusplus /* Licence: CC-BY */
#error "handle.h does not work with C++ compilers, you must compile these files with GCC directly!"
#endif
/** Tells your constructor/destructor handler function about the state */ /** Tells your constructor/destructor handler function about the state */
enum HANDLE_STATE { enum HANDLE_STATE {
HANDLE_CREAT, HANDLE_CREAT,
HANDLE_DESTR, HANDLE_DESTR
}; };
/** #ifndef __cplusplus
* This creates a "handle". Basically a struct with given constructor and destructor + RAII.
* #define creat(TNAME, VNAME, VINIT) \
* Usage: [[gnu::always_inline]] inline void VNAME##_cleanuper(struct TNAME *v) { \
TNAME##_lifetime_handler(HANDLE_DESTR, v, NULL); \
} \
[[gnu::cleanup(VNAME##_cleanuper)]] struct TNAME VNAME; \
TNAME##_lifetime_handler(HANDLE_CREAT, & VNAME, VINIT);
#define handle(TNAME) \
static inline void TNAME##_lifetime_handler( \
enum HANDLE_STATE state, \
struct TNAME *self, \
void *data)
#else /* C++ compilers better be able to compile code written with us */
#define creat(TNAME, VNAME, VINIT) \
TNAME##_raiicpp VNAME(VINIT);
#define handle(TNAME) \
struct TNAME##_raiicpp; \
static inline void TNAME##_lifetime_handler( \
enum HANDLE_STATE state, \
struct TNAME##_raiicpp *self, \
void *data); \
struct TNAME##_raiicpp : public TNAME { \
inline TNAME##_raiicpp(void *data) { \
TNAME##_lifetime_handler(HANDLE_CREAT, this, data); \
} \
inline ~TNAME##_raiicpp() { \
TNAME##_lifetime_handler(HANDLE_DESTR, this, nullptr); \
} \
}; \
static inline void TNAME##_lifetime_handler( \
enum HANDLE_STATE state, \
struct TNAME##_raiicpp *self, \
void *data)
#endif /* __cplusplus */
/*
* EXAMPLE:
* *
* struct Meaning { * struct Meaning {
* int a; * int a;
* int b; * int b;
* }; * };
* // You can typedef if you want, change code accordingly! * // You should not typedef this EVER!
* *
* handle(struct Meaning) { * handle(Meaning) {
* if(state == HANDLE_CREAT) { * if(state == HANDLE_CREAT) {
* this->a = *(int*) data; * self->a = *(int*) data;
* this->b = 2 * self->b = 2;
* } else { * } else {
* printf("%d\n", this->a + this->b); * printf("%d\n", self->a + self->b);
* } * }
* } * }
* *
@ -35,23 +71,9 @@ enum HANDLE_STATE {
* // Should print 42: * // Should print 42:
* int main() { * int main() {
* int initializer = 40; * int initializer = 40;
* creat(struct Data, d, &initializer); * creat(Meaning, d, &initializer);
* } * }
* *
* Rem.: Unrelated trick, but you can typedef struct A A; // both typedef and forward declare * Rem.: Unrelated trick, but you can typedef struct A A; // both typedef and forward declare
*/ */
#endif /* MAG_HANDLE_H */
#define creat(TNAME, VNAME, VINIT) \
[[gnu::always_inline]] inline void F(TNAME *v) { \
TNAME##_lifetime_handler(HANDLE_DESTR, v, NULL); \
} \
[[gnu::cleanup(F)]] TNAME VNAME; \
TNAME##_lifetime_handler(HANDLE_CREAT, VNAME, VINIT);
#define handle(TNAME) \
static void [[gnu::always_inline]] inline TNAME##_lifetime_handler( \
HANDLE_STATE state, \
TNAME *this, \
void *data)
#endif // MAG_HANDLE_H

View File

@ -1,4 +1,29 @@
#include <stdio.h> #include <stdio.h>
#include "handle.h"
int main() { struct Meaning {
int a;
int b;
};
handle(Meaning) {
if(state == HANDLE_CREAT) {
// Constructor
self->a = *(int*) data;
self->b = 2;
} else {
// Destructor
printf("%d\n", self->a + self->b);
}
}
// Now you can use a handle in your local scopes
// Should print 42:
int main() {
int initializer = 40;
creat(Meaning, d, &initializer);
initializer = 20;
creat(Meaning, d2, &initializer);
return 0;
} }

View File

@ -1,18 +1,27 @@
#include <stdio.h> #include <stdio.h>
int main() { int main() {
int a = 0; auto int a = 0;
int b = 40; int b = 20;
int c = 2; int c = 1;
int d = 0;
// See: https://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Nested-Functions.html // See: https://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Nested-Functions.html
inline void lf(register int* r) { inline auto void lf(register int *r) {
a += *r; a += *r;
int s = a + *r;
inline void deepfun() {
s *= 2;
}
deepfun();
d += s;
}; // semicolon(;) not needeed! }; // semicolon(;) not needeed!
/* /*
// Same as above... but need auto storage class if you pre-declare // Same as above... but need auto storage class if you pre-declare
inline auto void lf(register int* r); inline auto void lf(register int* r);
// ...
inline void lf(register int* r) { inline void lf(register int* r) {
a += *r; a += *r;
}; // semicolon(;) not needeed! }; // semicolon(;) not needeed!
@ -21,6 +30,6 @@ int main() {
lf(&b); lf(&b);
lf(&c); lf(&c);
printf("%d\n", a); printf("%d .. %d\n", a, d);
} }

View File

@ -8,6 +8,27 @@ gcc:
gcc raii_test.c -o raii_test gcc raii_test.c -o raii_test
g++ raii_test.cpp -o raii_test_cpp g++ raii_test.cpp -o raii_test_cpp
gcc handle_test.c -o handle_test gcc handle_test.c -o handle_test
gcc array_handle_test.c -o array_handle_test
g++ array_handle_test.c -o array_handle_test_cpp
gcc array_test.c -o array_test
g++ array_test.c -o array_test_cpp
gcc array_handle_gen_test.c -o array_handle_gen_test
g++ array_handle_gen_test.c -o array_handle_gen_test_cpp
debug:
gcc -g macroname.c -o macroname
gcc -g count.c -o count
gcc -g innerf.c -o innerf
# g++ innerf.c -o innerf_cpp # does not work :-(
gcc -g construct_destruct.c -o construct_destruct
gcc -g raii_test.c -o raii_test
g++ -g raii_test.cpp -o raii_test_cpp
gcc -g handle_test.c -o handle_test
gcc -g array_handle_test.c -o array_handle_test
g++ -g array_handle_test.c -o array_handle_test_cpp
gcc -g array_test.c -o array_test
g++ -g array_test.c -o array_test_cpp
gcc -g array_handle_gen_test.c -o array_handle_gen_test
g++ -g array_handle_gen_test.c -o array_handle_gen_test_cpp
clang: clang:
clang macroname.c -o macroname clang macroname.c -o macroname
clang count.c -o count clang count.c -o count
@ -16,3 +37,6 @@ clang:
clang construct_destruct.c -o construct_destruct clang construct_destruct.c -o construct_destruct
# clang raii_test.c -o raii_test # should not work # clang raii_test.c -o raii_test # should not work
clang++ raii_test.cpp -o raii_test_cpp clang++ raii_test.cpp -o raii_test_cpp
clang++ array_handle_gen_test.c -o array_handle_gen_test_clangpp
expand:
gcc -E handle_test.c -o handle_test_expanded.c

View File

@ -17,7 +17,7 @@ int main() {
cs += bytes[i]; cs += bytes[i];
} }
printf("Checksum of found bytes: %d\n", cs); printf("Checksum of found bytes: %d\n", (int) cs);
// exit(0); // This does not release resources! // exit(0); // This does not release resources!
return 0; return 0;