$ gcc -Wno-missing-declarations -std=c11 -fms-extensions -Wno-microsoft-anon-tag -o ex *.c && ./ex
Created
June 21, 2021 13:54
-
-
Save aschmidt75/33821c277ff72f90064ec228f18158c5 to your computer and use it in GitHub Desktop.
Example of c11 anonymous struct / Introduction of abstract interfaces
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __APP_ERROR_H | |
#define __APP_ERROR_H | |
#include <stdlib.h> | |
typedef struct error { | |
unsigned int code; | |
const char *msg; | |
struct error *wrapped; | |
} error; | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
/** | |
* gcc -Wno-missing-declarations -std=c11 -fms-extensions -Wno-microsoft-anon-tag -o x *.c && ./x | |
*/ | |
#include "sample_component_intf.h" | |
#include "sample_component.h" | |
/** | |
* main_usage uses an instance of a sample_component_intf. | |
* It onlyhas access to the function pointers defined in the | |
* interface part. It cannot use the internals | |
*/ | |
void main_usage(sample_interface *sci) { | |
sample_result_or_err res = sci->sample_function_1(sci, 3); | |
if (res.ok) { | |
printf("%d\n", res.sample_result); | |
} else { | |
printf("error: %d %s\n", res.err.code, res.err.msg); | |
} | |
} | |
/** | |
* main owns and creates a sample_component. It passes on | |
* its interface | |
*/ | |
int main(int argc, char **argv) { | |
sample_component* c = sample_component_new(); | |
main_usage((sample_interface*)c); | |
sample_component_delete(&c); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdbool.h> | |
#include "sample_component.h" | |
/** | |
* sample_component_private contains private variables | |
*/ | |
typedef struct sample_component_private { | |
int a; | |
} sample_component_private; | |
sample_result_or_err sample_component_sample_function_1(void* _this, int some_int); | |
/** | |
* implementation of sample_component_new | |
* allocate memory, set public variables, allocate memory for | |
* private fields, set private fields | |
*/ | |
sample_component* sample_component_new() { | |
sample_component* res; | |
res = (sample_component*)malloc(sizeof(sample_component)); | |
res->sample_function_1 = &sample_component_sample_function_1; | |
res->counter = 0; | |
res->private = (sample_component_private*)malloc(sizeof(sample_component_private)); | |
sample_component_private *p = (sample_component_private*)res->private; | |
p->a = 0; | |
return res; | |
} | |
void sample_component_delete(sample_component** c) { | |
if (*c != NULL) { | |
if ( (*c)->private != NULL) { | |
free((*c)->private); | |
(*c)->private = NULL; | |
} | |
free(*c); | |
*c = NULL; | |
} | |
} | |
/** | |
* implementation of sample_component_sample_function_1 | |
*/ | |
sample_result_or_err sample_component_sample_function_1(void* _this, int some_int) { | |
sample_component* this = (sample_component*)_this; | |
this->counter += 1; | |
sample_component_private *p = (sample_component_private*)this->private; | |
p->a = some_int; | |
if (p->a %2 == 0) { | |
sample_result_or_err res = { | |
.ok = true, | |
.sample_result = (p->a)+1 | |
}; | |
return res; | |
} | |
error e = { | |
.code = 15, | |
.msg = "Odd number detected" | |
}; | |
sample_result_or_err res = { | |
.ok = false, | |
.err = e | |
}; | |
return res; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __SAMPLE_COMPONENT_H | |
#define __SAMPLE_COMPONENT_H | |
#include "sample_component_intf.h" | |
/** | |
* Implementation side | |
* - sample_component implements sample_interface | |
* - only used by owning code. client code receives a pointer to the interface, not this struct | |
* - may contain additional fields, considered public | |
* - should have private variables hidden in the private struct | |
*/ | |
typedef struct sample_component { | |
// anonymously extend the interface (requires -fms-extensions) | |
struct sample_interface; | |
// public variables go here | |
int counter; | |
void *private; | |
} sample_component; | |
/** | |
* sample_component_new creates a new sample_component. | |
*/ | |
sample_component* sample_component_new(); | |
/** | |
* sample_component_delete frees memory | |
*/ | |
void sample_component_delete(sample_component**); | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __SAMPLE_COMPONENT_INTF_H | |
#define __SAMPLE_COMPONENT_INTF_H | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include "app_error.h" | |
/** | |
* A sample result struct, returned by an interface function | |
* - if ok == false, err contains the error | |
* - if ok == true, use the result | |
*/ | |
typedef struct sample_result_or_err { | |
const bool ok; | |
union { | |
const int sample_result; | |
const error err; | |
}; | |
} sample_result_or_err; | |
/** | |
* Interface part | |
* - focus on behaviour from perspective of client code | |
* - all functions as function pointers | |
* - do not reveal structural internals, use data transfer structs instead | |
* - return structs that combine a status and the result | |
*/ | |
typedef struct sample_interface { | |
/** | |
* sample_function_1 does sample things with some int | |
* @returns sample_result_or_err | |
*/ | |
sample_result_or_err (*sample_function_1)(void* sample_component_intf, int some_int); | |
} sample_interface; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment