Alternating behaviour of a function: How to detect function caller? - c

I have a function that toggles a flag everytime when it is called, which is done repeatedly, to have a alternating behaviour everytime the function is called. But what if i call the function multiple times, with different parameters? Of course my toggle-flag should only be toggled by the same function call. Is there a way to detect, have kind of a static behaviour of the flag, but one behaviour for each function caller?
void showText(uint8_t col, uint8_t line, const char *text, bool blinking)
{
if(blinking)
{
static bool flag = false;
if(flag)
{
lcd_setcursor(col, line);
for(int i = 0; i < strlen(text); i++)
{
lcd_data(' ');
}
}
else
{
lcd_setcursor(col, line);
lcd_string(text);
}
flag = !flag;
}
else
{
lcd_setcursor(col, line);
lcd_string(text);
}
}

void showText( uint8_t col, uint8_t line, const char *text, bool blinking, bool* flag_ptr ) {
...
if ( *flag_ptr ) { ... } else { ... }
*flag_ptr = !*flag_ptr;
...
}
Call site A:
static bool flag = false;
showText( ..., &flag );
Call site B:
static bool flag = false;
showText( ..., &flag );

You could also have the flag pointer be the decision for blinking itself:
static bool blinkstat1 = false;
static bool blinkstat2 = false;
// Show with blinking
showText(col1, line1, text1, &blinkstat1);
// Show with blinking
showText(col2, line2, text2, &blinkstat2);
// Show text1 again w/o blinking
showText(col1, line1, text1, NULL);
void showText(uint8_t col, uint8_t line, const char *text, bool* blinking ) {
lcd_setcursor(col, line);
if (blinking != NULL) {
// Blink
if ( *blinking ) {
for(int i = 0; i < strlen(text); i++) {
lcd_data(' ');
}
} else {
lcd_string(text);
}
*blinking = !*blinking;
} else {
// Just show text non-blinking
lcd_string(text);
}
}

Related

My while loop is not breaking after my interrupt updates in C

I am implementing simon says as a small weekly project for school. Using arduino Uno, I'm making 10 levels each level has an extra pattern inside. example: level 1: [1], level 2: [1,2], etc... I have three buttons on my shield. the interrupts work and everything is gucci. My problem here is in this snippet
bool readInput(uint8_t pattern[], uint8_t length)
{
sei();
uint8_t current = 0;
while (current < length)
{
btnPushed = false;
while (!btnPushed)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
printf("here");
cli();
_delay_ms(200);
if (currentPushed == pattern[current])
{
printf("correct, you pushed %d\n", currentPushed);
}
else
{
printf("incorrect, lets try again\n");
return false;
}
}
btnPushed = false;
return true;
}
so basically I set my buttonPushed to false, and start listening for interrupts, once its true after clicking, I expect to exit the loop and check the input, however my interrupt is correct and I get visual feedback with a light that lights up once i push a button.
this is my ISR
ISR(PCINT1_vect)
{
uint8_t buttonCurr = currentButton();
if (buttonCurr != -1)
{
if (!btn1Pushed && buttonCurr == 0)
{
btn1Pushed = true;
}
currentPushed = buttonCurr;
blinkLed(currentPushed, 1);
btnPushed = true;
}
}
my current button returns 0-2 for buttons that are clicked, and -1 if nothing was clicked.
this is the rest of my code, which is working pretty much
int currentPushed = -1;
bool won;
bool btnPushed = false;
bool btn1Pushed = false;
ISR(PCINT1_vect)
{
uint8_t buttonCurr = currentButton();
if (buttonCurr != -1)
{
if (!btn1Pushed && buttonCurr == 0)
{
btn1Pushed = true;
}
currentPushed = buttonCurr;
blinkLed(currentPushed, 1);
btnPushed = true;
}
}
int main(void)
{
enableAllButtons();
enableAllLeds();
lightDownAllLeds();
prepareButtonsForInterrupt();
initUSART();
init();
play();
if (won)
{
printf("Simon says you win");
}
else
{
printf("simon says do better");
}
return 0;
}
void init(void)
{
printf("LETS PLAY SIMON SAYS\nPress button 1 to start!\n");
int seed = 0;
while (!btn1Pushed)
{
blinkLed(3, 4);
seed++;
}
srand(seed);
printf("Get ready!\n");
btnPushed = false;
cli();
}
void createRandomPattern(uint8_t array[], uint8_t length)
{
for (int i = 0; i < length; i++)
{
array[i] = rand() % 3;
}
}
void play(uint8_t pattern[])
{
uint8_t fullPattern[MAX_PATTERN_LENGTH];
createRandomPattern(fullPattern, MAX_PATTERN_LENGTH);
for (int i = 1; i <= MAX_PATTERN_LENGTH; i++)
{
printf("========LEVEL %d===========\n", i);
playPuzzle(fullPattern, i);
#ifdef DEBUG
printPuzzle(fullPattern, i);
#endif
readInput(fullPattern, i) ?: i--;
}
}
bool readInput(uint8_t pattern[], uint8_t length)
{
sei();
uint8_t current = 0;
while (current < length)
{
btnPushed = false;
while (!btnPushed)
{
}
cli();
if (currentPushed == pattern[current])
{
printf("correct, you pushed %d\n", currentPushed);
}
else
{
printf("incorrect, lets try again\n");
return false;
}
current++;
}
btnPushed = false;
return true;
}
void printPuzzle(uint8_t pattern[], uint8_t length)
{
printf("[ ");
for (int i = 0; i < length; i++)
{
printf("%d ", pattern[i]);
}
printf("]\n");
}
void playPuzzle(uint8_t pattern[], uint8_t length)
{
for (int i = 0; i < length; i++)
{
lightUpOneLed(pattern[i]);
_delay_ms(500);
lightDownOneLed(pattern[i]);
}
}
btnPushed is defined as bool btnPushed = false;.
So when you write:
while (!btnPushed)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
Nothing in the loop will change btnPushed so there is no point for the compiler to ever check btnPushed again. So what the compiler sees is this:
if (!btnPushed)
while(true)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
You have to tell the compiler that the value of btnPushed will change unexpectantly when the interrupt fires by using:
volatile bool btnPushed = false;

How to trigger creation of savefile

I'm trying to create a libretro core. It will be a standalone game, so I'm setting RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME to true. The documentation suggests that retro_get_memory_* can be used to have data saved without needing to explicitly query RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY:
The save directory should be used to
store SRAM, memory cards, high scores, etc, if the libretro core
cannot use the regular memory interface (retro_get_memory_data()).
How should the core trigger the saving of data using this interface? Or am I misunderstanding the documentation?
I would expect the frontend to call retro_get_memory_{data,size}, read from the exposed buffer when stopping the core, persist the data to disk, and write it back to the exposed buffer the next time the core starts. Instead I observe:
If I don't provide a content file, the frontend never calls retro_get_memory_{data,size}.
If I provide a content file (which is unused), the frontend calls retro_get_memory_{data,size} after retro_load_game but doesn't write to disk.
Note that this question is about save files (automatically persisted data, usually capturing the player's progress), not save states (snapshots of the game state triggered by the user) which are implemented by the *serialize* methods.
Here is a simple example to reproduce the issue (based on this sample):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libretro.h"
static unsigned char c = 0;
void* retro_get_memory_data(unsigned id) {
fprintf(stderr, "retro_get_memory_data(%d)\n", id);
return (id == RETRO_MEMORY_SAVE_RAM) ? &c : NULL;
}
size_t retro_get_memory_size(unsigned id) {
fprintf(stderr, "retro_get_memory_size(%d)\n", id);
return (id == RETRO_MEMORY_SAVE_RAM) ? 1 : 0;
}
#define WIDTH 320
#define HEIGHT 240
static uint32_t* frame_buf;
void retro_init(void) { frame_buf = calloc(WIDTH * HEIGHT, sizeof(uint32_t)); }
void retro_deinit(void) {
free(frame_buf);
frame_buf = NULL;
}
unsigned retro_api_version(void) { return RETRO_API_VERSION; }
void retro_get_system_info(struct retro_system_info* info) {
memset(info, 0, sizeof(*info));
info->library_name = "SaveTest";
info->library_version = "v1";
info->need_fullpath = false;
info->valid_extensions = NULL; // Anything is fine, we don't care.
}
static retro_video_refresh_t video_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
void retro_set_environment(retro_environment_t cb) {
environ_cb = cb;
bool no_content = true;
cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content);
}
void retro_get_system_av_info(struct retro_system_av_info* info) {
float aspect = (float)WIDTH / HEIGHT;
info->timing = (struct retro_system_timing){
.fps = 60.0,
.sample_rate = 0.0,
};
info->geometry = (struct retro_game_geometry){
.base_width = WIDTH,
.base_height = HEIGHT,
.max_width = WIDTH,
.max_height = HEIGHT,
.aspect_ratio = aspect,
};
}
unsigned retro_get_region(void) { return RETRO_REGION_NTSC; }
bool retro_load_game(const struct retro_game_info* info) {
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
fprintf(stderr, "XRGB8888 is not supported.\n");
return false;
}
(void)info;
return true;
}
bool button(unsigned id) {
return input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, id);
}
void retro_run(void) {
input_poll_cb();
if (button(RETRO_DEVICE_ID_JOYPAD_LEFT) && c > 0) --c;
if (button(RETRO_DEVICE_ID_JOYPAD_RIGHT) && c < 255) ++c;
uint32_t color = (255 - c) | (c << 8);
uint32_t* buf = frame_buf;
for (unsigned i = WIDTH * HEIGHT; i > 0; --i) {
*buf = color;
++buf;
}
video_cb(frame_buf, WIDTH, HEIGHT, WIDTH * sizeof(uint32_t));
}
void retro_unload_game(void) {}
size_t retro_serialize_size(void) { return 1; }
bool retro_serialize(void* data, size_t size) {
fprintf(stderr, "serialize(%p, %lu) <= %u\n", data, size, c);
*(char*)data = c;
return true;
}
bool retro_unserialize(const void* data, size_t size) {
c = *(char*)data;
fprintf(stderr, "unserialize(%p, %lu) => %u\n", data, size, c);
return true;
}
void retro_set_controller_port_device(unsigned port, unsigned device) {}
void retro_set_audio_sample(retro_audio_sample_t cb) {}
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) {}
void retro_reset(void) {}
bool retro_load_game_special(unsigned type, const struct retro_game_info* info,
size_t num) {
return false;
}
void retro_cheat_reset(void) {}
void retro_cheat_set(unsigned index, bool enabled, const char* code) {}
It is undocumented but intended that auto save does not trigger for a core without content.
Moreover auto save was not triggering for cores which had content but could support no content. This was unintended and recently fixed.
Reference: https://github.com/libretro/RetroArch/issues/9300

How to wait an input without stop the program in Xlib

The problem is this, I, am writing a chip 8 emulator in C, and i am using a library that use Xlib, for writing sprites attending input etc, the method that the library have for wait an input is this:
char gfx_wait(){
XEvent event;
gfx_flush();
while(1) {
XNextEvent(gfx_display,&event);
if(event.type==KeyPress) {
saved_xpos = event.xkey.x;
saved_ypos = event.xkey.y;
return XLookupKeysym(&event.xkey,0);
} else if(event.type==ButtonPress) {
saved_xpos = event.xkey.x;
saved_ypos = event.xkey.y;
return event.xbutton.button;
}
}
}
when i call this method the program stops waiting for input, I, need a methods that is called just when i press or release a button.
I just solve my problem, using this function :
int gfx_event_waiting(unsigned char *ch)
{
XEvent event;
gfx_flush();
while (1) {
if(XCheckMaskEvent(gfx_display,-1,&event)) {
if(event.type==KeyPress) {
*ch = XLookupKeysym(&event.xkey,0);
return 1;
}else if(event.type==KeyRelease){
return 1;
}else if (event.type==ButtonPress) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
}
and this is the main :
int
main(int argc, char *argv[])
{
int x;
int i;
unsigned char key_pressed,key_released;
Init();
LoadRom(SELECTED_ROM);
gfx_open(WIDTH,HEIGHT,"Chip 8 Emulator");
gfx_color(255,250,250);
for(;;){
if(!gfx_event_waiting(&key_pressed)){
opcode_cycle();
key_wait(key_released,0);
#if DEBUG
printf("# %d | %c #",x,key_pressed);
#endif
key_wait(key_pressed,1);
key_released = key_pressed;
gfx_clear();
if(DrawFlag)
Draw();
/*Big for for simulate a delay*/
for(i = 0; i <= 100000; i++)
;
}else{
x++;
}
}
}
I, am sure that there is a better way for do this , but you know, It's work...

How do I check the call order of different functions in C

in order to set a certain variable (MyVariable) to "TRUE" I have to check that a specific function call order was respected within a system.
For example, I have different functions within the system:
uint8 myFunction1()
{
if (...)
{
return NOT_OK
}
else
{
return OK
}
}
uint8 myFunction2()
{
if (...)
{
return NOT_OK
}
else
{
return OK
}
}
uint8 myFunction3()
{
if (...)
{
return NOT_OK
}
else
{
return OK
}
}
MyVariable = TRUE only if:
OK == myFunction1
OK == myFunction2
OK == myFunction3
exactly this call order was respected.
How to check the call order in C but without touching the body of the functions (like setting some flags´etc.)?
I'm still beginner and experimenting with C :)
Thanks!
This is almost certainly an "XY problem". That is, you think saving the call order is the solution to your actual problem, but your actual problem might be to ensure that the functions can't be called in the wrong order in the first place.
So the most correct way to fix this is to remake the program design. Someone mentioned state machines as one solution. Another solution might be something like an array of function pointers (which is a common implementation of state machines).
That being said, you can do something artificial to track the call order, though I wouldn't really recommend it. Example:
#define CALL_ORDER_N 3
const char* call_order [CALL_ORDER_N] = {NULL};
size_t call_order_i = 0;
static void save_call (const char* func)
{
call_order[call_order_i] = func;
call_order_i++;
if(call_order_i == CALL_ORDER_N)
{
call_order_i = 0;
}
}
Where call_order saves the 3 last function calls as pointers to string literals. The function save_call updates this array, by passing the __func__ constant to it from each function. __func__ is guaranteed to work like a static const char[] so this is safe. You'd do something like this:
void myFunction1 (void)
{
save_call(__func__);
...
}
void myFunction2 (void)
{
save_call(__func__);
...
}
void myFunction3 (void)
{
save_call(__func__);
...
}
And then go through the calls to see if they were in the correct order:
static bool is_call_order_ok (void)
{
const char* expected_order [CALL_ORDER_N] =
{
"myFunction1",
"myFunction2",
"myFunction3"
};
size_t co_i = call_order_i;
for(size_t i=0; i<CALL_ORDER_N; i++)
{
if(strcmp(call_order[co_i], expected_order[i])==0)
{
co_i++;
if(co_i == CALL_ORDER_N)
{
co_i = 0;
}
}
else
{
return false;
}
}
return true;
}
Full example:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#define CALL_ORDER_N 3
const char* call_order [CALL_ORDER_N] = {NULL};
size_t call_order_i = 0;
static void save_call (const char* func)
{
call_order[call_order_i] = func;
call_order_i++;
if(call_order_i == CALL_ORDER_N)
{
call_order_i = 0;
}
}
static bool is_call_order_ok (void)
{
const char* expected_order [CALL_ORDER_N] =
{
"myFunction1",
"myFunction2",
"myFunction3"
};
size_t co_i = call_order_i;
for(size_t i=0; i<CALL_ORDER_N; i++)
{
if(strcmp(call_order[co_i], expected_order[i])==0)
{
co_i++;
if(co_i == CALL_ORDER_N)
{
co_i = 0;
}
}
else
{
return false;
}
}
return true;
}
void myFunction1 (void)
{
save_call(__func__);
}
void myFunction2 (void)
{
save_call(__func__);
}
void myFunction3 (void)
{
save_call(__func__);
}
int main (void)
{
printf("Call 1,2,3: ");
myFunction1();
myFunction2();
myFunction3();
printf(is_call_order_ok() ? "Ok\n" : "Failed\n");
printf("Call 3,2,1: ");
myFunction3();
myFunction2();
myFunction1();
printf(is_call_order_ok() ? "Ok\n" : "Failed\n");
printf("Call 1,1,1: ");
myFunction1();
myFunction1();
myFunction1();
printf(is_call_order_ok() ? "Ok\n" : "Failed\n");
return 0;
}
The advanced, more professional version of the above, would be to cook together a mini-API with a single function, in order to give private encapsulation to every single variable. The function save_call would then be a multi-purpose function, that can be used to register expected call order, save function calls, as well as verify if the current registered order is ok.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#define CALL_ORDER_N 3
static bool save_call (const char* func, bool verify)
{
bool result;
static const char* call_order [CALL_ORDER_N] = {NULL};
static size_t call_order_i = 0;
static const char* expected_order [CALL_ORDER_N] = {NULL};
size_t i = call_order_i;
if(verify) // special case, verify the order
{
for(size_t expected=0; expected<CALL_ORDER_N; expected++)
{
if(call_order[i] == expected_order[expected])
{
i++;
if(i == CALL_ORDER_N)
{
i = 0;
}
}
else
{
return false;
}
}
return true;
}
if(expected_order[i] == NULL) // register order of calls
{
expected_order[i] = func;
result = true;
}
else // save calls
{
call_order[i] = func;
result = false;
}
call_order_i++;
if(call_order_i == CALL_ORDER_N)
{
call_order_i = 0;
}
return result;
}
void myFunction1 (void)
{
if(save_call(__func__, false))
return ;
printf("Execute stuff in %s.\n", __func__);
}
void myFunction2 (void)
{
if(save_call(__func__, false))
return ;
printf("Execute stuff in %s.\n", __func__);
}
void myFunction3 (void)
{
if(save_call(__func__, false))
return ;
printf("Execute stuff in %s.\n", __func__);
}
int main (void)
{
/* register call order: */
myFunction1();
myFunction2();
myFunction3();
printf("Call 1,2,3:\n");
myFunction1();
myFunction2();
myFunction3();
printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");
printf("Call 3,2,1:\n");
myFunction3();
myFunction2();
myFunction1();
printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");
printf("Call 1,1,1:\n");
myFunction1();
myFunction1();
myFunction1();
printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");
return 0;
}
save_call should of course be properly placed in a .h/.c file pair of its own.
There is no direct and portable way. That being said, debuggers are great at breaking execution flow when a function is reached, so you could either use a debugger, or use debugging functions to be warned when the functions are called (unfortunately nothing portable here).
Alternatively, some linkers allow to hide some identifiers and replace them so with custom (and advanced) link options you could replace all call to those functions with calls to custom wrappers. But here again it would only makes sense for a specific implementation so it is not a C way either.
Anyway, this is such an uncommon requirement that I cannot imagine the actual reasonning behind. Maybe you could give more context about your real problem...

managing if statements

gcc 4.4.3 c89
I have some functions that initialize some hardware and return either true or false. If false then I have to uninitialize in the reverse order.
However, my code is looking very untidy with all the if statements.
For example each function can return either true of false. This is a sample. As you can see the code looks very untidy. I am just looking for any advice on how I can clean it up to make it more manageable and if possible scable?
Many thanks for any advice,
if(init_A() == TRUE) {
if(init_B() == TRUE) {
if(init_C() == TRUE) {
if(init_D() == TRUE) {
if(init_E() == TRUE) {
/* ALL STARTED OK */
}
else {
uninit_A();
uninit_B();
uninit_C();
uninit_D();
}
}
else {
uninit_A();
uninit_B();
uninit_C();
}
}
else {
uninit_A();
uninit_B();
}
}
else {
/* Failed to initialize B */
uninit_B();
}
}
else {
/* Failed to start */
}
if(init_A() != TRUE) {
goto EndA;
}
if(init_B() != TRUE) {
goto EndB;
}
if(init_C() != TRUE) {
goto EndC;
}
if(init_D() != TRUE) {
goto EndD;
}
if(init_E() != TRUE) {
goto EndE;
}
...
return;
EndE: uninitD();
EndD: uninitC();
EndC: uninitB();
EndB: uninitA();
EndA: return;
This is quite a common problem, where the "init" steps correspond to things like malloc() or lock(), and the "uninit" steps correspond to things like free() and unlock(). It is particularly an issue when resources have to be deallocated in strictly the reverse order in which they were allocated.
This is one case where the use of goto is justified:
int somefunc()
{
int retval = ERROR;
if (init_A() != TRUE)
goto out_a;
if (init_B() != TRUE)
goto out_b;
if (init_C() != TRUE)
goto out_c;
if (init_D() != TRUE)
goto out_d;
if (init_E() != TRUE)
goto out_e;
/* ALL STARTED OK */
/* ... normal processing here ... */
retval = OK;
uninit_E();
out_e:
uninit_D();
out_d:
uninit_C();
out_c:
uninit_B();
out_b:
uninit_A();
out_a:
return retval;
}
I would loop through an array of function pointers, call the functions in the loop, then if that function returned false, perform the corresponding uninit_* function.
Here's an example:
void (*inits[5]) (void);
void (*uninits[4]) (void);
int main(void) {
inits[0] = init_A;
inits[1] = init_B;
inits[2] = init_C;
inits[3] = init_D;
inits[4] = init_E;
uninits[0] = uninit_A;
uninits[1] = uninit_B;
uninits[2] = uninit_C;
uninits[3] = uninit_D;
for(int i = 0; i < 5; i++) {
if((*inits[i])() != TRUE) {
int j = (i < 4) ? i : 4;
while(j--) {
(*uninits[j])();
}
break;
}
}
return 1;
}
BOOL a = FALSE, b = FALSE, c = FALSE, d = FALSE, e = FALSE;
if ( (a = init_A()) && (b = init_B()) && (c = init_C()) && (d = init_D()) && (e = init_E()) )
{
}
else
{
if ( e ) uninit_E();
if ( d ) uninit_D();
if ( c ) uninit_C();
if ( b ) uninit_B();
if ( a ) uninit_A();
}
uninit functions are called in direct order, as in your code. If reverse order is required, just change this.
If your uninit_* functions can detect whether or not they need to do anything you can simply:
if (!init_A() || !init_B() || !init_C() || !init_D() )
{
uninit_C();
uninit_B();
uninit_A();
return FALSE;
}
Is that "reverse order"? For me reverse order is like this:
void uninit(int from) {
switch (from) {
/* ... */
case 3: uninit_C(); /* fall_through */
case 2: uninit_B(); /* fall_through */
case 1: uninit_A(); /* fall_through */
case 0: break;
}
}
And the init process would go like this
int count = 0;
if (init_A()) {
count++;
if (init_B()) {
count++;
if(init_C()) {
count++;
if(init_D()) {
count++;
if(init_E()) {
count++;
}
}
}
}
}
if (count == 5) /* ALL OK */;
uninit(count);
Limited understanding of C at work here, if you do decide to downvote, please tell me why.
#include <stdio.h>
int init_a() { return 1; }; // succeed
int init_b() { return 1; }; // succeed
int init_c() { return 0; }; // fail
void uninit_a() { printf("uninit_a()\n"); }
void uninit_b() { printf("uninit_b()\n"); }
void uninit_c() { printf("uninit_c()\n"); }
typedef struct _fp {
int (*init)();
void (*uninit)();
} fp;
int init() {
fp fps[] = {
(fp){&init_a, &uninit_a},
(fp){&init_b, &uninit_b},
(fp){&init_c, &uninit_c}
};
unsigned int i = 0, j;
for(; i < sizeof(fps) / sizeof(fp); ++i) {
if(!(*fps[i].init)()) {
for(j = 0; j < i; ++j) {
(*fps[j].uninit)();
}
return -1;
}
}
return 0;
}
int main() {
init();
return 0;
}
Output:
uninit_a()
uninit_b()
This is the same order that the code in original post would be executed in, but you may want to reverse it (inner loop).
What you perhaps are looking for is "scope bound resource management". C++ traditionally does that with constructors/destructors. But there is a way to do that differently (in C99 as well as in C++) by abusing the for-statement a bit. I wrote something up upon this line here:
scope bound resource management with for scopes.
I've not got a compiler to try this out. But something like this might work?
int (*init[])() = {init_A, init_B, init_C, init_D, init_E};
int (*uninit[])() = {uninit_A, uninit_B, uninit_C, uninit_D, uninit_E};
int main()
{
initfunction(init, 0)
return 0;
}
void initfunction((*init[])(), pos)
{
if(init[pos]() == TRUE)
initfunction(init, pos++)
else
return;
uninit[pos]();
}
int X = 0;
if(init_A() == TRUE) {
X++;
if(init_B() == TRUE) {
X++;
if(init_C() == TRUE) {
X++;
if(init_D() == TRUE) {
X++;
if(init_E() == TRUE) {
X++;
/* ALL STARTED OK */
}
}
}
}
}
/* You said reverse order which I took to mean this,
* though your did not do it this way. */
switch (X) {
case 5:
return SUCCESS;
case 4:
uninit_D();
case 3:
uninit_C();
case 2:
uninit_B();
case 1:
uninit_A();
return FAILURE;
}
Something I find myself doing to prevent myself from making errors in code like this is:
static int do_A(void);
static int do_B(void);
static int do_C(void);
static int do_D(void);
static int do_A(void) {
if (init_A() == FALSE) {
return FALSE;
}
if (do_B() == FALSE) {
uninit_A();
return FALSE;
}
return TRUE;
}
...
static int do_D(void) {
return init_D();
}
All of the other do_ functions should look similar to do_A.

Resources