Does it matter where in my program I call atexit()? - c

Basically, I am writing a program in SDL.
This is part of the code:
// create game window
game.window = SDL_CreateWindow(
"Game",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
160,
144,
0
);
if (game.window == NULL)
{
fprintf(stderr, "Window error: %s\n", SDL_GetError());
return 1;
}
atexit(SDL_DestroyWindow());
atexit(SDL_Quit());
return 0;
}
My question is the following. Considering the procedural nature of C, what happens if (game.window == NULL) is the case and return 1 executes. Does the program terminate with return 1 without calling the atexit() functions that come after this if-statement?
Does the program still call SDL_DestroyWindow() and SDL_Quit(), which are both in atexit() functions despite the atexit() functions coming after the return 1 in the if (game.window == NULL)-statement?
As far as I understand, C executes code from top to bottom, so how would it know to call the functions in atexit() at the end if return 1 happens before?

You're right, it wont call those functions registered with atexit().
To show this behaviour I wrote a small code snippet.
#include <stdlib.h>
#include <stdio.h>
void bye()
{
printf("Bye!\n");
}
int main(int argc, char *argv[])
{
int i = 1;
if (i) {
printf("Ending\n");
return 0;
}
atexit(bye);
return 0;
}
And this won't print the "Bye!", as the atexit() is registered after the check for i.

First of all, you cannot destroy the window before you know for true you have it created So the call to atexit(3) to register the function to destroy the window must be done after you know the window exists. (this is after the } closing bracket of the if)
The call to atexit(SDL_Quit); might be done once you have the SDL environment intialized (this is after it has been correctly inited, so it will be called only for a truly intialized environment) but it must be called before the call to register the destroy of the SDL window, as atexit(3) makes the functions you register, to be called in reverse order so it must first desroy the window and then close the SDL environment (and there will be no sense to call a function that destroys a window when the SDL has already been closed).
By the way, atexit() requires the function pointers, not the result of the function call. Better to write
atexit(SDL_Quit);
atexit(SDL_DestroyWindow);
Than what you have written.
NOTE
If the functions need parameters, better to write function wrappers to call them with the appropiate parameters.

Related

Why should I not use exit function in C? [duplicate]

This question already has answers here:
Should we use exit() in C?
(7 answers)
Closed 7 years ago.
I've been making some school project and I've used this function for error outputs:
void errorMsg(char* msg)
{
fprintf(stderr, msg);
exit(EXIT_FAILURE);
}
So I can do something like this:
if (condition)
errorMsg("Error, Wrong parameters.");
Message will be shown to user and program will exit with error code.
But I've recieved minus points for using exit function.
So I was just wondering how should I do it? Is there some another way than writing this for several times in main function?
if (condition)
{
fprintf(stderr, "Error, Wrong parameters.");
return(EXIT_FAILURE);
}
Thanks for you time.
It really depends on how you program, or in this case, how your teacher wants you to program.
The best answer at this case, is to go to your teacher and ask for an explanation why this is wrong.
When I program in C, all my functions always return int (or a typedef of int) and then I can return errors from functions. Then my main function returns an error as it returns. Something like this template:
int func(void)
{
int return_value = 0;
if (/* Some condition */) {
return_value = 1
}
/* Some code */
return return_value;
}
int main(void)
{
int return_value = 0;
return_value = func();
return return_value
}
Using this template, if there is an error, 1 would be returned from the main function, and in case of success, 0 would be returned. As well, you can add an if condition in the main function, to check the return value of func. This gives you the option to handle errors in your code.
One important reaons:
If you have some code which has opened files, but not yet finished to write in them, and this piece of code delegates some work to a function that will end the program, what happens?
Right, you´ll get a broken file.
Same reasoning is valid for allocated memory, open handles of any kind, etc.etc.
Instead of thinking everytime if the function could end the program, don´t write such functions in the first place. It doesn´t matter if everything is ok or not, but return the "control" after a function to the caller everytime. The only place where exit could be ok is main, because it will basically do the same thing as return there. And in main, there´s no reason to not write return in the first place.
My opinion is that exit functions are harder to test. I struggled a lot while testing a function that has exit call.

Better to return(EXIT_FAILURE) to main or exit(EXIT_FAILURE) in function instead?

I have a basic question regarding proper program structure in c.
Let's say my main function calls several other functions to configure a specific piece of hardware (like an ethernet card), and that each of those functions calls more basic functions to deal with more specific configuration on that ethernet card.
The the lower level functions all have return values that specify whether they were completed successfully. Is it most proper to continue this paradigm all the way back to main?
For example, if one of my lower level functions fails, should I be doing the following?:
check its return value --> return to calling function --> check its return value --> return to calling function ...
all the way back to main?
Or does it make more sense to have main just assume everything is functioning normally (not considering return values of the functions it calls) and returning 0; then calling exit(EXIT_FAILURE) from the lower level functions?
I greatly appreciate the help.
For academia level applications, I don't think it matters.
.
However, for production (enterprise) applications, my (30-years) experience is:
1) Never call exit() unless it's a last resort, where the user needs to
contact the application developer to resolve an unanticipated condition.
2) In order to ensure maintainability, functions should not contain more
than one return statement.
All of the functions I produce (for use in an enterprise production environment) have a similar flow:
int SomeEnterpriseQualityFunction(
SOME_TYPE1_T I__someValueBeingPassedIntoTheFunction,
...
SOME_TYPE2_T *IO_someValueBeingModifiedByTheFunction,
...
SOME_TYPE3_T **_O_someValueBeingReturnedByTheFunction
)
{
int rCode=0;
int someFileHandle=(-1);
void *someMemory = NULL;
SOME_TYPE3_T *someValueBeingReturnedByTheFunction=NULL;
/* Validate user input parameters */
if( /*I__someValueBeingPassedIntoTheFunction is out of range */)
{
rCode=ERANGE;
goto CLEANUP;
}
if( NULL == IO_someValueBeingModifiedByTheFunction )
{
rCode=EINVAL;
goto CLEANUP;
}
/* Acquire resources */
someFileHandle=open(/*someFileName, mode, etc.*/);
if((-1) == someFileHandle)
{
rCode=errno;
goto CLEANUP;
}
someMemory=malloc(/* bytesToMalloc */);
if(NULL == someMemory)
{
rCode=ENOMEM;
goto CLEANUP;
}
/* Actual work done here. */
....
if(/* Successfully finished work at this point... */)
goto RESULT;
...
...
/* Return results to caller here. */
RESULT:
if(_O_someValueBeingReturnedByTheFunction);
{
*_O_someValueBeingReturnedByTheFunction = someValueBeingReturnedByTheFunction;
someValueBeingReturnedByTheFunction = NULL;
}
/* Release acquired resources. */
CLEANUP:
if(someValueBeingReturnedByTheFunction)
{
int rc= /* Clean-up someValueBeingReturnedByTheFunction related resources,
since the caller didn't need it. */
if(0==rCode)
rCode=rc;
}
if(someMemory)
free(someMemory);
if((-1) != someFileHandle)
{
if((-1) == close(someFileHandle) && 0 == rCode)
rCode=rc;
}
return(rCode);
}
And, not matter what your instructors might say about goto, they are far from -evil- when used in this way for error handling.
There are multiple separate issues here.
As for whether you should propagate errors up or just call exit(EXIT_FAILURE) at the point you detect a problem, I'd generally recommend propagating the errors up. If the low-level code propagates the error up, it leaves open the possibility that the higher-level code could try to handle the error (e.g., report it to the user, retry, try a different configuration, etc.). If the low-level code bails out, the higher level code doesn't have a chance to deal with it. (The flipside is that the higher level code has to be prepared to do something appropriate and not just carry on assuming there were no errors.)
As for what those errors values should be, I'd generally recommend defining your own return status types (e.g., as an enum). EXIT_FAILURE and EXIT_SUCCESS are intended to be inputs to exit, and you should treat them as opaque values. For example, don't assume that EXIT_SUCCESS is 0.
As for whether you should return from main or call exit, that's up to you. To be super-hyper-portable, I recommend calling exit with EXIT_SUCCESS or EXIT_FAILURE as appropriate. However, it's common to simply return 0 for success or return nonzero for failure. The latter practice doesn't work well on some obscure, mostly dead operating systems with brain-dead compilers. In any event, I would never return EXIT_SUCCESS from main.
In my opinion, calling exit( EXIT_FAILURE ) right from the failing function is okay. If some cleanup is necessary, then I would use atexit()
From http://linux.die.net/man/3/exit
#include <stdlib.h>
void exit(int status);
The exit() function causes normal process termination ...
All functions registered with atexit(3) and on_exit(3) are called,
in the reverse order of their registration.

Calling different User Define Functions in C

Sorry if I seem stupid for asking this but I want to reinforce my understanding and clear any misconceptions I have about user define functions.
"Case:"
I have two functions (can be either void or int) which I will call them function1 and function2.
I have them in a file that will be called by other programs.
I have function1 as a void function called in another program and will keep being called until the program ends (function2 will not run when function1 is running).
Function2 must be executed by another program(not the same program for function1) calls for function2 (function1 must not be running in this case). Function2 can be an int or void function.
I know that the standard procedure would to put them in order in my main function since this program will call main only. The main will run in the order of the functions placed (e.g. function1 will run first then function2)
eg
#include<stdio.h>
#include<stdlib.h>
void function1(....)
int function2(...)
void function1(intA,intB,struct.....)
{
...Conditions, loops, whatever
}
int function2()
{
..........
return(some value)
}
In this part, I would have the main at the bottom
int main(int argc, char *argv[])
{
function1();
int A;
A = function2();
....
}
I thought that I would use if else conditions in main to make "Case:" possible.
Would this sample code run exactly as I mentioned at the top under Case: (with if else conditions)? If not, what am I getting confused? Example code in c would help very much as well with clear explanations.
Please tell me if there is something confusing with my explanation or my question. I will try to make it clear.
If you want to call only one function, use a command line parameter which you get via argv/argc.
int main(int argc, char *argv[])
{
if (argc != 2) return -1; // zero or 2+ commandline arguments
if (0 == strcmp(argv[1], "function1"))
function1();
else if (0 == strcmp(argv[1], "function2"))
function2();
else { return -1; /* error */ }
return 0;
}
What happens behind the scenes (before main() is called), a partial list:
OS creates new prrocess and executes it's entry point address (not main()).
Entry point function receives all command line arguments from the OS in some OS dependent manner.
Various C std library are called to initialize the framework.
Environment variables are copied to std C library structures.
Dependent DLL's are loaded.
Globals are initialized.
An array of char* is created (argv). Each array entry points to a C string. The first (argv[0]) is always the exe name. If the OS/shell have passed command line arguments, they are copied to argv[1], argv[2], etc.
main(int, char**) is called with argv and argc.
All this work is done to abstract the OS from the program. The above flow is heavily OS dependent and doesn't interest most developers. When you're an (very) advanced C programmer or if you take an interest in this flow then you can read on your own.
main() prototype is defined by the C standard. Actually there are several legal prototypes to choose from. The compiler/linker will choose what you implement.

Can 1 return invoke 2 returns?

This is mostly theoretical question as there's not much use in it.
consider this situation :
function a() {
return;
}
function b(){
a();
}
Can you invoke a return in a parent function from a child one?
Now in this case you can simpley do return a(); and that will happen but let's say you're intrested of not preforming a return.
I know that when translating it to assembly this doesn't make sense, in this case u can use goto but we all know how dangerous that is.
My logic says that if you can preform a continue from a child loop that will invoke continue on the parent, this should be the same, but loops doesn't affect the stack so it makes sense that continue does work.
I am wondering if there's any way to handle this case witjout using events or the oop approach?
The traditional C solution is the longjmp function, which can jump an arbitrary way up the stack. Mind you, there have always been people who were wise enough not to use it, and it has been largely succeeded by exception handling.
You could use a macro instead of a function.
#define a() ... return ...
A use case would be asserts that are not completely removed in a release build, but abort a function:
#define REQUIRE(x) do { assert((x)); if (!(x)) return; } while (0)
You can also hack something in assembler to get the stackframe of the calling functions and use the return address from there:
void return2(){
void * frame;
#if (defined(x86_64) || defined(__x86_64__))
__asm__(
"pop %rbp\n" //skip over stack frame of return2
"mov %rsp, %rbp\n"
"pop %rax\n"
"pop %rbp\n" //skip over stack frame of caller
"mov %rsp, %rbp\n"
"pop %rax\n"
);
#else
#error only implmented for amd64...
#endif
}
Then
void a(){
printf("a 0\n");
return2();
printf("a 1\n");
}
void b(){
printf("b 0\n");
a();
printf("b 1\n");
}
int main(int argc, char* argv[])
{
printf("main 0\n");
b();
printf("main 1\n");
return 0;
}
prints
main 0
b 0
a 0
main 1
This is the most dangerous solution from all (and it fails if gcc inlines something or removes the stackframe at higher optimization levels. But you could add a check that examines the instructions, if they were optimized )
If you are on Windows using MSVC, you can use exceptions (Strucured Exception Handling, SEH) to achive something similar. On other platforms you can use setjmp/longjmp, as thiton said.
With SEH, you could do something like the following (haven't tried it since I have no Windows with Visual Studio ready):
#include "stdio.h"
#include "Windows.h"
void func_b() {
printf("In func_b()\n");
// return safely to main
RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL);
printf("At end of func_b()\n");
}
void func_a() {
printf("In func_a()\n");
func_b();
printf("At end of func_a()\n");
}
void main() {
printf("In func_a()\n");
__try {
func_a();
}
__except (GetExceptionCode() == 1) {
printf ("Early return to main()\n");
}
printf("At end of main()\n");
}
The RaiseException call causes control to go up the stack until the exception is caught, in main(). This is not really "return^2", because the calling function (main) has to play along. In general, you'll also need cooperation of the functions you want to jump through (here func_a), since they might do stuff and need cleanup. Just saying "return from func_b, and stop whatever func_a was doing and return from that, too" can be very dangerous. If you use exceptions, however, you can wrap your code in func_a in try/finally clause:
FILE* f;
__try {
f = fopen("file.txt", "r");
func_b();
}
__finally {
fclose(f);
printf("Cleanup for func_a()\n");
}
This is of course much nicer in languages that natively support exceptions (C++, Python, Java, ...), and don't just have it bolted on as a proprietary extension.
Note that some people regard it as bad practice to use exceptions for control flow, and say exceptions should be reserved for truely exceptional events (like IO errors). There are a buch of cases where it does make sense (e.g. you're parsing something, and realize deep down the stack that you have to rewind and parse something differently, you can throw a custom exception). In general, I'd say try not to be too clever, and try not to do things that will confuse readers of your program. When it seems you need to use some trick like this, there's often a way to restructure the program to do it in a way that's natural for the language. Or maybe the language your using is not a good choice for the problem.

What is weird about wrapping setjmp and longjmp?

I am using setjmp and longjmp for the first time, and I ran across an issue that comes about when I wrap setjmp and longjmp. I boiled the code down to the following example:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jb;
int mywrap_save()
{
int i = setjmp(jb);
return i;
}
int mywrap_call()
{
longjmp(jb, 1);
printf("this shouldn't appear\n");
}
void example_wrap()
{
if (mywrap_save() == 0){
printf("wrap: try block\n");
mywrap_call();
} else {
printf("wrap: catch block\n");
}
}
void example_non_wrap()
{
if (setjmp(jb) == 0){
printf("non_wrap: try block\n");
longjmp(jb, 1);
} else {
printf("non_wrap: catch block\n");
}
}
int main()
{
example_wrap();
example_non_wrap();
}
Initially I thought example_wrap() and example_non_wrap() would behave the same. However, the result of running the program (GCC 4.4, Linux):
wrap: try block
non_wrap: try block
non_wrap: catch block
If I trace the program in gdb, I see that even though mywrap_save() returns 1, the else branch after returning is oddly ignored. Can anyone explain what is going on?
The longjmp() routines may not be called after the routine which called
the setjmp() routines returns.
In other words, you are screwing up your stack.
You might take a look at the assembly to see if you can piece together what's really happening.
setjmp() will save the current call stack and mark a point. When the call stack grows, no matter how far from the marked point, you can use longjmp() to go to the marked point, like you never left the point.
In your code, when returning from mywrap_save(), the marked point was no longer valid, the stack space around the point was dirty, hence you cannot go back to a dirty point.

Resources