Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > How to exit out of a function ? what is try-catch-throw in terms of Program Counter

Reply
Thread Tools

How to exit out of a function ? what is try-catch-throw in terms of Program Counter

 
 
Joel Yliluoma
Guest
Posts: n/a
 
      10-23-2007
On Sat, 20 Oct 2007 20:45:58 -0000, wrote:
> NOTE: I am really afraid of try-catch-throw. I have never been
> able to understand it since it does not exist in C and I cant
> really visualize the construct in terms of C.


How try-catch-throw is actually implemented depends on the compiler,
but one can explain it like this.

Assume the following C++ code is written:

#include <cstdio>

// here's a sample object with a constructor and destructor
// to demonstrate scope.
class someobj
{
public:
someobj() { std:uts("constructor"); }
~someobj() { std:uts("destructor"); }
private:
int x; // a dummy member variable
};

// A dummy type, it could be a typedef of int or whatever.
// Just for the purpose of throwing an exception of this particular type.
struct someexceptiontype
{
};

void code_that_may_throw()
{
someobj obj; // instantiating someobj in this scope.

if(false != true)
{
// some error situation happened, throw an exception.
// someexceptiontype() instantiates an object of
// "someexceptiontype" (without binding it into a variable),
// and throw throws it.
throw someexceptiontype();
}

std:uts("wow, false is true");
}

void some_intermediate_function()
{
std:uts("1");
code_that_may_throw();
std:uts("2");
}

int main()
{
try
{
some_intermediate_function();
std:uts("executed without hitch");
}
catch(int e)
{
std:uts("caught an int");
}
catch(someexceptiontype e)
{
std:uts("caught someexceptiontype");
}
std:uts("end of main()");
return 0;
}

The code above contains high-level concepts that approximately translate
to the following lower-level concepts in C. It could be implemented
differently, but the function is the same.

#include <stdio.h>

typedef struct someobj
{
int x;
} someobj;

void someobj__construct(someobj* this)
{
puts("constructor");
if(__system_exception_ptr) goto __scope_end;
__scope_end: ;
}
void someobj__destruct(someobj* this)
{
puts("destructor");
if(__system_exception_ptr) goto __scope_end;
__scope_end: ;
}

struct someexceptiontype
{
};

/*** This global code is defined in some system library by the compiler */
void* __system_exception_ptr = (void*)0;
int __system_exception_type = 0;
void __clear_exception()
{
__system_exception_type = 0;
free(__system_exception_ptr);
__system_exception_ptr = (void*)0;
}
/*** End of compiler library code */

void code_that_may_throw(void)
{
someobj obj; // instantiating someobj in this scope.
someobj__construct(&obj);
if(__system_exception_ptr) goto __scope_end_before_obj;

if(0 != 1)
{
someexceptiontype* e = (someexceptiontype*) malloc(sizeof(*e));
__system_exception_ptr = e;
__system_exception_type = 2;
/* ^ a compiler-specific tag that identifies the exception type */
goto __scope_end;
}

puts("wow, false is true");
if(__system_exception_ptr) goto __scope_end;

__scope_end: ;
someobj__destruct(&obj);
__scope_end_before_obj: ;
}

void some_intermediate_function(void)
{
puts("1");
if(__system_exception_ptr) goto __scope_end;

code_that_may_throw();
if(__system_exception_ptr) goto __scope_end;

puts("2");
if(__system_exception_ptr) goto __scope_end;
__scope_end: ;
}

int main(void)
{
some_intermediate_function();
if(__system_exception_ptr) goto try_catch;
puts("executed without hitch");
if(__system_exception_ptr) goto try_catch;
goto past_catch;
try_catch: ;
switch(__system_exception_type)
{
case 1: /* example denoting int type */
{
__clear_exception();
puts("caught an int");
if(__system_exception_ptr) goto __scope_end;
break;
}
case 2: /* example denoting someexceptiontype */
{
__clear_exception();
puts("caught someexceptiontype");
if(__system_exception_ptr) goto __scope_end;
break;
}
default:
goto __scope_end; /* still not caught */
}
past_catch: ;
puts("end of main()");
if(__system_exception_ptr) goto __scope_end;

__scope_end: ;
return 0;
}

Of course, for efficiency reasons there is no "if" test after every
function return for exceptions (rather, execution may be transferred
to a dedicated stack and scope unfolder when an exception happens),
but this was the easiest way to explain what happens as regards for
scopes and execution paths.
Also, in the exception handler (catch {}), the exception object is
not supposed to be deallocated until the end of the handler, but
for simplicity I wrote the deallocation first.

Followups set to comp.lang.c++ .

--
Joel Yliluoma - http://bisqwit.iki.fi/
: comprehension = 1 / (2 ^ precision)
 
Reply With Quote
 
 
 
 
Stefan Monnier
Guest
Posts: n/a
 
      10-23-2007
> NOTE: I am really afraid of try-catch-throw. I have never been
> able to understand it since it does not exist in C and I can't
> really visualize the construct in terms of C. That is what my


Actually, these constructs pretty much exist in C as well: `catch' is called
`setjmp', and `throw' is called `longjmp'.


Stefan
 
Reply With Quote
 
 
 
 
gnuist006@gmail.com
Guest
Posts: n/a
 
      10-23-2007
On Oct 23, 9:33 am, Stefan Monnier <monn...@iro.umontreal.ca> wrote:
> > NOTE: I am really afraid of try-catch-throw. I have never been
> > able to understand it since it does not exist in C and I can't
> > really visualize the construct in terms of C. That is what my

>
> Actually, these constructs pretty much exist in C as well: `catch' is called
> `setjmp', and `throw' is called `longjmp'.
>
> Stefan


Is it in some obscure corner of K&R ANSI ? I was never taught this one
by my instructor. Can you explain its syntax and patterns of usage ?

 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      10-23-2007
Stefan Monnier wrote:
>> NOTE: I am really afraid of try-catch-throw. I have never been
>> able to understand it since it does not exist in C and I can't
>> really visualize the construct in terms of C. That is what my

>
> Actually, these constructs pretty much exist in C as well: `catch' is
> called `setjmp', and `throw' is called `longjmp'.


I believe a better way would be to imagine that 'try', not 'catch',
is called 'setjmp'.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask


 
Reply With Quote
 
gnuist006@gmail.com
Guest
Posts: n/a
 
      10-23-2007
On Oct 23, 9:33 am, Stefan Monnier <monn...@iro.umontreal.ca> wrote:
> > NOTE: I am really afraid of try-catch-throw. I have never been
> > able to understand it since it does not exist in C and I can't
> > really visualize the construct in terms of C. That is what my

>
> Actually, these constructs pretty much exist in C as well: `catch' is called
> `setjmp', and `throw' is called `longjmp'.
>
> Stefan


Stefan, let me thank you for what seems to me to be the correct
concept.
I searched this whole thread in google for setjmp and YOU are the only
one who mentioned it. I applaud you. Because, it does not seem that
there
is any other construct that can implement try-catch-throw. I still
have to
read up on it, but thats what my gut instinct says.

Anyone, care to show how this translates into assembly after we deal
thoroughly with this in the context of C ?

Everyone, please ignore the the mean spirits trying to derail a
serious
conceptual discussions and calling each other trolls or giving
obfuscated
explanations for ego purposes, and not LUCID explanation.


 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-23-2007
* :
> On Oct 23, 9:33 am, Stefan Monnier <monn...@iro.umontreal.ca> wrote:
>>> NOTE: I am really afraid of try-catch-throw. I have never been
>>> able to understand it since it does not exist in C and I can't
>>> really visualize the construct in terms of C. That is what my

>> Actually, these constructs pretty much exist in C as well: `catch' is called
>> `setjmp', and `throw' is called `longjmp'.
>>
>> Stefan

>
> Stefan, let me thank you for what seems to me to be the correct
> concept.
> I searched this whole thread in google for setjmp and YOU are the only
> one who mentioned it.


Uh, have you plonked me, then?

I think that my reply was the very first reply in the thread.

I suggest you read that article again, because it contains some
important details not mentioned by Stefan et.al.


- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
gnuist006@gmail.com
Guest
Posts: n/a
 
      10-23-2007
On Oct 20, 3:55 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * gnuist...@gmail.com:
>
>
>
> > I have some code like this:

>
> > (if (test)
> > (exit)
> > (do something))

>
> > or

>
> > (if (test)
> > ( do something)
> > (exit))

>
> > Various levels of nestings.

>
> > I have several questions, basic to sophisticated.

>
> > (1) What is the lisp equivalent idiom for (exit) as in bash or
> > in C.

>
> C++ does not have a built-in 'exit' command. There is a library
> function 'exit' which exits the process. One must assume that's not
> what you mean, and that you're not asking C and C++ programmers to teach
> you Lisp.
>
> Therefore, assuming you want to exit the function or the block.
>
> > (2) What is the best practice to handle this kind of problems?

>
> It's not a general class of problem.
>
> Appropriate solutions depend on the problem at hand.
>
> E.g., in C++,
>
> // (if (test) (exit) (do something))
>
> void foo()
> {
> if( !test )
> {
> doSomething();
> }
> }
>
> void bar()
> {
> if( test ) { return; }
> doSomething();
> }
>
> > (3) What is the intermediate practice to handle this kind of
> > problems.

>
> ?
>
> > NOTE: I am really afraid of try-catch-throw. I have never been
> > able to understand it since it does not exist in C and I cant
> > really visualize the construct in terms of C. That is what my
> > brain can process. If you understand it so well, you can show
> > me how one would really implement that kind of construct in
> > C and then by extension I can see that kind of program flow
> > in LISP. Whether its imperative programming or functional,
> > beneath there is program counter and assembly. C is close
> > to machine so much that it is almost assembly. So understanding try-c-
> > t in C is equivalent to understanding at
> > the level of machine language.

>
> The closest equivalent in C would be a 'longjmp'. However, a C++
> exception is more limited, in that it will only jump up the call chain,
> and it's more powerful, in that it will destroy local objects as it does
> so. Also, if you use 'longjmp' in C++ you're practically doomed (unless
> you use it to jump between co-routines with their own stacks), because
> 'longjmp' doesn't destroy local objects.


Sure you have good ideas.

I still would like an equivalent implementation explained. Ofcourse,
smart
companies and smart programmers were doing all this before C++ came
and even in LISP they have atleast two of try catch throw.

 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-23-2007
* :
> On Oct 20, 3:55 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> The closest equivalent in C would be a 'longjmp'. However, a C++
>> exception is more limited, in that it will only jump up the call chain,
>> and it's more powerful, in that it will destroy local objects as it does
>> so. Also, if you use 'longjmp' in C++ you're practically doomed (unless
>> you use it to jump between co-routines with their own stacks), because
>> 'longjmp' doesn't destroy local objects.

>
> Sure you have good ideas.


Note that some people could read that as an attempt at insulting.


> I still would like an equivalent implementation explained. Ofcourse,
> smart
> companies and smart programmers were doing all this before C++ came
> and even in LISP they have atleast two of try catch throw.


Ada introduced to the wider community much that was subsequently adopted
in C++. Interestingly, (much of) the STL was implemented in Ada before
it was implemented in C++. And perhaps also interestingly, Ada's high
level thread primitives are seemingly now /not/ considered for C++.

Now as for equivalence, you don't really want C code, because that would
have to emulate C++ objects!

But in C++ such longjm-based code is hairy compiler-dependent stuff,
with formally Undefined Behavior.

Also, as an example of equivalent-except-for-efficiency, note that a
call of a virtual function can be specified equivalently as a dynamic
lookup in most derived class, base class, base class' base class and so
on, a search up the base class chain, but is in actuality implemented as
a table look-up (with all compilers). Exceptions are implemented in
more than just one main way. However, analogously to the case with
virtual functions, equivalent code that performs dynamic lookup, such as
the code below, is extremely ineffecient compared to the Real Thing(TM).

Depending on the actual implementation of exceptions, there can be no
overhead at all for normal case code.


<code>
#include <vector>
#include <csetjmp>
#include <string>
#include <iostream>
#include <ostream>

#if defined( _MSC_VER )
# define LNGJMP_DESTROYS_AUTOMAGICALLY

#elif defined( __GNUC__ )
# undef LNGJMP_DESTROYS_AUTOMAGICALLY
# // No automatic destruction, at least in MingW 3.4.4 version.

#else
# error Your compiler is not supported by this program.
#endif

struct AbstractLngjmpCleanup
{
virtual ~AbstractLngjmpCleanup() {}
virtual void destroy() = 0;
};

template< typename T >
struct LngjmpCleanup: AbstractLngjmpCleanup
{
T* myTarget;
LngjmpCleanup( T& target ): myTarget( &target ) {}
virtual void destroy()
{
#ifndef LNGJMP_DESTROYS_AUTOMAGICALLY
myTarget->T::~T(); // Call destructor on target.
#endif
}
};

struct LongjmpCleanups
{
std::vector<AbstractLngjmpCleanup*> myDestroyers;

~LongjmpCleanups()
{
for( size_t i = 0; i < myDestroyers.size(); ++i )
{
delete myDestroyers.at( i );
}
}

template< typename T >
void add( T& target )
{
myDestroyers.push_back( new LngjmpCleanup<T>( target ) );
}

void destroyAll()
{
for( size_t i = 0; i < myDestroyers.size(); ++i )
{
myDestroyers.at( i )->destroy();
}
}
};

template< typename T >
void say( T const& v ) { std::cout << v << std::endl; }

struct Whatever
{
std::string myId;
Whatever( std::string id ): myId( id )
{ say( "Constructed " + myId + "." ); }

~Whatever()
{ say( "Destroyed " + myId + "." ); }
};


jmp_buf* pReturnAddress = 0;

void bottom()
{
LongjmpCleanups destroyers;
LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers );

Whatever localObject( "bottom()'s local object" );

destroyers.add( localObject );

say( "Executing body of bottom()." );

say( "Throwing simulated exception." );
{
destroyers.destroyAll();
destroyersDestroyer.destroy();
longjmp( *pReturnAddress, 1 );
}
}

void middle()
{
jmp_buf returnAddress;
jmp_buf* pOldReturnAddress;
LongjmpCleanups destroyers;
LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers );

Whatever localObject( "middle()'s local object" );

destroyers.add( localObject );
pOldReturnAddress = pReturnAddress;
if( setjmp( returnAddress ) == 0 )
{
pReturnAddress = &returnAddress;

say( "Executing body of middle(), calling bottom()." );
bottom();

pReturnAddress = pOldReturnAddress;
}
else
{
destroyers.destroyAll();
destroyersDestroyer.destroy();
pReturnAddress = pOldReturnAddress;
longjmp( *pReturnAddress, 1 );
}
}

void top()
{
jmp_buf returnAddress;
jmp_buf* pOldReturnAddress;
LongjmpCleanups destroyers;
LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers );

Whatever localObject( "top()'s local object" );

destroyers.add( localObject );
pOldReturnAddress = pReturnAddress;
if( setjmp( returnAddress ) == 0 )
{
pReturnAddress = &returnAddress;

say( "Executing body of top(), calling middle()." );
middle();

pReturnAddress = pOldReturnAddress;
}
else
{
destroyers.destroyAll();
destroyersDestroyer.destroy();
pReturnAddress = pOldReturnAddress;
longjmp( *pReturnAddress, 1 );
}
}

int main()
{
jmp_buf returnAddress;

pReturnAddress = &returnAddress;
if( setjmp( returnAddress ) == 0 )
{
say( "Main business code, calling top()..." );
top();
return EXIT_SUCCESS;
}
else
{
say( "Caught simulated exception!" );
return EXIT_FAILURE;
}
}
</code>

<output>
Main business code, calling top()...
Constructed top()'s local object.
Executing body of top(), calling middle().
Constructed middle()'s local object.
Executing body of middle(), calling bottom().
Constructed bottom()'s local object.
Executing body of bottom().
Throwing simulated exception.
Destroyed bottom()'s local object.
Destroyed middle()'s local object.
Destroyed top()'s local object.
Caught simulated exception!
</output>

Now I leave it as an exercise to reimplement this program to use C++
exceptions instead of longjmp, and perhaps compare clarity (and
efficiency, if that's interesting).

Cheers, & hth.,

- Alf


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Joel Yliluoma
Guest
Posts: n/a
 
      10-24-2007
On Tue, 23 Oct 2007 12:33:17 -0400, Stefan Monnier wrote:
>> NOTE: I am really afraid of try-catch-throw. I have never been
>> able to understand it since it does not exist in C and I can't
>> really visualize the construct in terms of C. That is what my

>
> Actually, these constructs pretty much exist in C as well:
> `catch' is called `setjmp', and `throw' is called `longjmp'.


If you ignore the thing about scope that I was being very careful
to illustrate properly, then yes.
And, the fact that try-catch blocks can be nested, recursed, etc,
and only catching the matching type of exception stops the unwinding.

--
Joel Yliluoma - http://bisqwit.iki.fi/
: comprehension = 1 / (2 ^ precision)
 
Reply With Quote
 
Stefan Monnier
Guest
Posts: n/a
 
      10-24-2007
>>> NOTE: I am really afraid of try-catch-throw. I have never been
>>> able to understand it since it does not exist in C and I can't
>>> really visualize the construct in terms of C. That is what my

>>
>> Actually, these constructs pretty much exist in C as well: `catch' is
>> called `setjmp', and `throw' is called `longjmp'.


> I believe a better way would be to imagine that 'try', not 'catch',
> is called 'setjmp'.


Sorry, I'm reading this on gnu.emacs.help where Elisp only provides `catch'
and `throw' (no `try') and these map pretty closely to setjmp/longjmp.


Stefan
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
Page File counter and Private Bytes Counter George2 C++ 1 01-31-2008 09:27 AM
How to exit out of a function ? what is try-catch-throw in terms of Program Counter gnuist006@gmail.com C++ 34 12-02-2007 11:51 PM
Code to Exit Web App and Exit Internet Explorer =?Utf-8?B?U2FuZHk=?= ASP .Net 7 08-05-2005 01:55 AM
Session("counter") vs. ViewState("counter")...a newbie question The Eeediot ASP .Net 3 12-22-2004 09:31 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57