Need experts opnion

V

vashwath

Hi all,
In my current project I am thinking to use setjmp/lngjmp for exception
handling.The way I am planing to do this is shown in the below example.
Please if this is the right way to do.Are there any disadvantages in
this method?

#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf g_env;
extern void fun1();
int main()
{
int ret;

ret = setjmp(g_env);
if (ret == 0)
{
printf("Perform the intended functionality");
fun1();
exit(EXIT_SUCCESS);
}
else
{
printf("Exception handling\n");
exit(EXIT_FAILURE);
}

}


#include <stdio.h>
#include <setjmp.h>

extern jmp_buf g_env;

void fun1()
{
longjmp(g_env,1);
}
 
T

tmp123

Hi all,
In my current project I am thinking to use setjmp/lngjmp for exception
handling.The way I am planing to do this is shown in the below example.
Please if this is the right way to do.Are there any disadvantages in
this method?

#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf g_env;
extern void fun1();
int main()
{
int ret;

ret = setjmp(g_env);
if (ret == 0)
{
printf("Perform the intended functionality");
fun1();
exit(EXIT_SUCCESS);
}
else
{
printf("Exception handling\n");
exit(EXIT_FAILURE);
}

}


#include <stdio.h>
#include <setjmp.h>

extern jmp_buf g_env;

void fun1()
{
longjmp(g_env,1);
}



Hi,

Starting with the code you has post, there are several posible
improvements:

1) Do not use a single jmp_buf, but an array of it.
2) Define macros to made more visible the exception handling. Only as
an example:

#define TRY if (setjmp(g_env))
#define CATCH else
#define THROW(x) longjmp(g_env,x)

mades the code

TRY
{
}
CATCH
{
}

....


THROW(1)

3) Do not forget the falg volatile when necessary.

Kind regards.
 
C

Chuck F.

In my current project I am thinking to use setjmp/lngjmp for
exception handling.The way I am planing to do this is shown in
the below example. Please if this is the right way to do.Are
there any disadvantages in this method?
*** quote munged to reduce vertical space ***
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf g_env;
extern void fun1();
int main()
{
int ret;

ret = setjmp(g_env);
if (ret == 0) {
printf("Perform the intended functionality");
fun1();
exit(EXIT_SUCCESS);
}
else {
printf("Exception handling\n");
exit(EXIT_FAILURE);
}
}

#include <stdio.h>
#include <setjmp.h>

extern jmp_buf g_env;

void fun1()
{
longjmp(g_env,1);
}

Surprise. Your very first statement "ret = setjmp(...)" is
illegal! The following is a quote from N869:

Environmental limits

[#4] An invocation of the setjmp macro shall appear only in
one of the following contexts:

-- the entire controlling expression of a selection or
iteration statement;

-- one operand of a relational or equality operator with
the other operand an integer constant expression, with
the resulting expression being the entire controlling
expression of a selection or iteration statement;

-- the operand of a unary ! operator with the resulting
expression being the entire controlling expression of a
selection or iteration statement; or

-- the entire expression of an expression statement
(possibly cast to void).

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
V

vashwath

Chuck said:
Surprise. Your very first statement "ret = setjmp(...)" is
illegal! The following is a quote from N869:

Environmental limits

[#4] An invocation of the setjmp macro shall appear only in
one of the following contexts:

-- the entire controlling expression of a selection or
iteration statement;

-- one operand of a relational or equality operator with
the other operand an integer constant expression, with
the resulting expression being the entire controlling
expression of a selection or iteration statement;

-- the operand of a unary ! operator with the resulting
expression being the entire controlling expression of a
selection or iteration statement; or

-- the entire expression of an expression statement
(possibly cast to void).
I am not able to understand any of these points. Can anybody explain in
simpler way(if possible with an example)?
Thanks in Advance
 
T

tmp123

Could you please explain in detail why jmp_buf should be an array?

If you have an array of similar, you can have nested TRYs, in same or
different procedures.

Kind regards.
 
F

Flash Gordon

Chuck said:
Surprise. Your very first statement "ret = setjmp(...)" is
illegal! The following is a quote from N869:

Environmental limits

[#4] An invocation of the setjmp macro shall appear only in
one of the following contexts:

-- the entire controlling expression of a selection or
iteration statement;

-- one operand of a relational or equality operator with
the other operand an integer constant expression, with
the resulting expression being the entire controlling
expression of a selection or iteration statement;

-- the operand of a unary ! operator with the resulting
expression being the entire controlling expression of a
selection or iteration statement; or

-- the entire expression of an expression statement
(possibly cast to void).
I am not able to understand any of these points. Can anybody explain in
simpler way(if possible with an example)?
Thanks in Advance

You are not allowed to do something like
ret = setjmp(...);
You should do something like:
if (setjmp(...)...)
or:
if (!setjmp(...))
or:
switch (setjmp(...)) {
...
}
You can also just have a line:
setjmp(...);
I.e. not using the value returned.
 
C

Christian Bau

Hi all,
In my current project I am thinking to use setjmp/lngjmp for exception
handling.The way I am planing to do this is shown in the below example.
Please if this is the right way to do.Are there any disadvantages in
this method?

One problem with any kind of exception handling is that exceptions
thrown will return to the exception handling code, skipping all function
calls in between. Any cleanup that is required by functions between the
initial caller and the place where the exception is thrown will not be
executed.

In Java, this problem is partially solved by having garbage collection.
Just organise your code so that throwing away dynamically allocated
objects will be enough to clean up. In C++, this problem is partially
solved by having destructors. Just organise your code so that
destructing any objects on the stack will be enough to clean up. In C,
there is no such thing. Any cleanup has to be done manually. You will
find yourself in major trouble very soon.

Unless you want to put superhuman effort into exception handling, the
only thing you can do in C is using setjmp/longjmp to cover complete
major subsystems; allocating all memory through functions that keep
track of allocation and free all memory when an exception happens,
installing function pointers for cleanup when necessary. This is a major
operation that needs experienced and diligent programmers.
 
V

vashwath

In Java, this problem is partially solved by having garbage collection.
Just organise your code so that throwing away dynamically allocated
objects will be enough to clean up.

If I intialize all the pointers used for allocating memory to NULL and
call free on all these pointers uppon exception, then I have cleaned up
successfully is'nt it?
 
T

tmp123

Christian said:
One problem with any kind of exception handling is that exceptions
thrown will return to the exception handling code, skipping all function
calls in between. Any cleanup that is required by functions between the
initial caller and the place where the exception is thrown will not be
executed.

In Java, this problem is partially solved by having garbage collection.
Just organise your code so that throwing away dynamically allocated
objects will be enough to clean up. In C++, this problem is partially
solved by having destructors. Just organise your code so that
destructing any objects on the stack will be enough to clean up. In C,
there is no such thing. Any cleanup has to be done manually. You will
find yourself in major trouble very soon.

Unless you want to put superhuman effort into exception handling, the
only thing you can do in C is using setjmp/longjmp to cover complete
major subsystems; allocating all memory through functions that keep
track of allocation and free all memory when an exception happens,
installing function pointers for cleanup when necessary. This is a major
operation that needs experienced and diligent programmers.


I agree on the previous (the reference to Java memory handling could be
completed with some security issues? and nested tries must be
referenced?).

However, the advantages of exceptions are also important. (Well, in
fact, nobody doubts today about benefits of exceptions, so, I'm being
redundant)

See two examples of a usual code with an without:

char * getLine( void )
{
FILE *f=NULL;
char *r=NULL;

if ( (r=malloc_string() == NULL ) return NULL;
if ( (f=file_open() == NULL )
{
/* Mixed messages and code!*/
fprintf(stderr, "unable to alloc...);
free(r);
return NULL;
}
if ( fgets(...) ... )
{
fprintf(stderr, "unable to ...);
free(r);
fclose(f); /* error handling grows! */
return NULL;
}
...
fclose(f);
return r;
}

char * getLines( const char *name )
{
FILE *f=NULL;
char *r=NULL;

TRY
{
f=file_open();
r=malloc_string();
if ( fgets(...) ... ) THROW(EXC_FAIL_READ);
...
fclose(f);
}
CATCH
{
if ( f != NULL ) fclose(f);
if ( r != NULL ) free(r);
r = NULL;
/* write errro messages or keep it in the main TRY */
THROW_NEXT;
}
END_TRY
return r;
}
 
C

Chuck F.

tmp123 said:
.... snip ...

However, the advantages of exceptions are also important. (Well,
in fact, nobody doubts today about benefits of exceptions, so,
I'm being redundant)

See two examples of a usual code with an without:

char * getLine( void )
{
FILE *f=NULL;
char *r=NULL;

if ( (r=malloc_string() == NULL ) return NULL;
if ( (f=file_open() == NULL )
{
/* Mixed messages and code!*/
fprintf(stderr, "unable to alloc...);
free(r);
return NULL;
}
if ( fgets(...) ... )
{
fprintf(stderr, "unable to ...);
free(r);
fclose(f); /* error handling grows! */
return NULL;
}
...
fclose(f);
return r;
}

Here is my rewrite of that:

char * getLine(void)
{
FILE *f = NULL;
char *r, *rv = NULL;

if (!(r = mallocstring())) fprintf(stderr, "alloc..");
else if (!(f = file_open()) fprintf(stderr, "file ..");
else if (!fgets(...)) fprintf(stderr, "read ...");
else {
rv = r;
....
}
if (!rv) free(r);
if (f) fclose(f);
return rv;
}

(which I believe has the identical function, and has a single point
of return.) In practice I would probably postpone the malloc until
I had determined that the file would open.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
E

Eric Sosman

Christian said:
Hi all,
In my current project I am thinking to use setjmp/lngjmp for exception
handling.The way I am planing to do this is shown in the below example.
Please if this is the right way to do.Are there any disadvantages in
this method?


One problem with any kind of exception handling is that exceptions
thrown will return to the exception handling code, skipping all function
calls in between. Any cleanup that is required by functions between the
initial caller and the place where the exception is thrown will not be
executed.

In Java, this problem is partially solved by having garbage collection.
[...]

And more thoroughly solved by the try/finally construct.
The lack of something analogous is what makes exception-like
constructs in "plain C" vulnerable to the problem you describe.
Solving the problem in "plain C" isn't impossible, but involves
more than simply calling setjmp() and longjmp() -- for example,
you'll need to be able to form chains of contexts so an exception
thrown in f() can cause cleanup actions in e() and d() and c()
and b() before being caught in a(). The machinery to manage the
context chains needn't be elaborate, but must be carefully crafted.
 
C

Christian Bau

If I intialize all the pointers used for allocating memory to NULL and
call free on all these pointers uppon exception, then I have cleaned up
successfully is'nt it?

But how do you do this? (Code is just for illustration, no guarantee
that it compiles or works)

void function_throwing_exception ()
{
longjmp (jmpbuf, 1);
}

void function_in_the_middle ()
{
char* p = NULL;
char* q = NULL;
char* r = NULL;

p = malloc (100);
q = malloc (100);
r = malloc (100);
function_throwing_exception ();
free (r);
free (q);
free (p);
}

void caller ()
{
jmp_buf jmpbuf;
if (setjmp (jmpbuf))
{
function_in_the_middle ();
}
}

Now tell me how you clean up p, q and r when the exception is thrown.
 
T

tmp123

But how do you do this? (Code is just for illustration, no guarantee
that it compiles or works)

void function_throwing_exception ()
{
longjmp (jmpbuf, 1);
}

void function_in_the_middle ()
{
char* p = NULL;
char* q = NULL;
char* r = NULL;

p = malloc (100);
q = malloc (100);
r = malloc (100);
function_throwing_exception ();
free (r);
free (q);
free (p);
}

void caller ()
{
jmp_buf jmpbuf;
if (setjmp (jmpbuf))
{
function_in_the_middle ();
}
}

Now tell me how you clean up p, q and r when the exception is thrown.

As some others person have said, nested TRYs. Nothing new, same than in
C++ and others. Something more or less like:

void function_throwing_exception ()
{
THROW(1);
}

void function_in_the_middle ()
{
char* p = NULL;
char* q = NULL;
char* r = NULL;

TRY
{
p = malloc (100);
q = malloc (100);
r = malloc (100);
function_throwing_exception ();
free (r);
free (q);
free (p);
}
CATCH
{
free (r);
free (q);
free (p);
THROW_BACKWARD;
}
}

void caller ()
{
TRY
{
function_in_the_middle ();
}
...
}

My conclusion about this subject: use C++ compilers, even if the
keyword "class" is not used, except if no available or other hard
specification restrictions.
 
C

Chuck F.

If I intialize all the pointers used for allocating memory to
NULL and call free on all these pointers uppon exception, then I
have cleaned up successfully is'nt it?

No. You also have to invert the order of allocation. Think of
linked lists or trees.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
C

Chris Torek

My conclusion about this subject: use C++ compilers, even if the
keyword "class" is not used, except if no available or other hard
specification restrictions.

And what happens when you use a C++ compiler on the following
C program? (Note, it is stripped-down to make the problem more
apparent. If the problem is not immediately obvious, compile it
as both C and C++ and run both versions.)

#include <stdio.h>

struct A { char a[100]; };

int main(int argc, char **argv) {
struct B { struct A { char a; } b; } b;

printf("sizeof(struct A) = %lu\n",
(unsigned long)sizeof(struct A));
return 0;
}

(Although this particular example is stripped-down and looks
contrived, this was actually a real issue in a real program
in which someone carelessly attempted to mix C and C++ code.)
 
R

Richard Bos

tmp123 said:
void function_throwing_exception ()
{
THROW(1);
}

void function_in_the_middle ()
{
char* p = NULL;
char* q = NULL;
char* r = NULL;

TRY
{
p = malloc (100);
q = malloc (100);
r = malloc (100);
function_throwing_exception ();
free (r);
free (q);
free (p);
}
CATCH
{
free (r);
free (q);
free (p);
THROW_BACKWARD;
}
}

void caller ()
{
TRY
{
function_in_the_middle ();
}
...
}

My conclusion about this subject: use C++ compilers, even if the
keyword "class" is not used, except if no available or other hard
specification restrictions.

"Good" advice... since the code above does not compile under C++,
because that language is broken-as-designed where void * is involved.

Richard
 
T

tmp123

Richard said:
"Good" advice... since the code above does not compile under C++,
because that language is broken-as-designed where void * is involved.

Richard

Also "..." can cause problems, and the lack of definition for TRY, and
others.
It is somekind of joke?
 
R

Richard Bos

tmp123 said:
Also "..." can cause problems, and the lack of definition for TRY, and
others.

Those can be corrected with good C code. The point I refer to cannot.

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top