Contents of an exception object


J

James Harris

Although C has no support for exceptions it seems easy enough with some
programming discipline to achieve a similar effect - or at least one that
suits my purposes: basically to throw an exception at one level and catch it
higher up the call stack.

Where the exception is thrown I had in mind creating an object (i.e. a
struct) to represent some details about the exception. My question is about
what you guys would suggest to include in that object, i.e. things which are
simple in C to include and yet potentially useful. To illustrate, the call
to create the exception might be something like

excep_throw( .... );

This function would create an object to describe what was found to be wrong
and then trigger the exception handling mechanism. The mechanism is
unimportant here but what things would be good to include in the parens?
Some possibilities:

* the type of exception (an unsigned int)
* the function name (as a string?)
* __FILE__ and/or __LINE__ (if possible)
* a message string
* parameters (somehow)

Any thoughts on that? Anyone already done something similar?

James
 
Ad

Advertisements

J

James Kuyper

Although C has no support for exceptions it seems easy enough with some
programming discipline to achieve a similar effect - or at least one that
suits my purposes: basically to throw an exception at one level and catch it
higher up the call stack.

Where the exception is thrown I had in mind creating an object (i.e. a
struct) to represent some details about the exception. My question is about
what you guys would suggest to include in that object, i.e. things which are
simple in C to include and yet potentially useful. To illustrate, the call
to create the exception might be something like

excep_throw( .... );

This function would create an object to describe what was found to be wrong
and then trigger the exception handling mechanism. The mechanism is
unimportant here but what things would be good to include in the parens?
Some possibilities:

* the type of exception (an unsigned int)
* the function name (as a string?)

For C99 and later, initialize the function name from __func__.
* __FILE__ and/or __LINE__ (if possible)
* a message string

When throwing from inside a loop, the current value of the loop counter
would also provide some useful information.
* parameters (somehow)

I would think it would be more useful to restrict your attention to the
values of variables (whether or not they are parameters) appearing in
the condition expression, that have more than one value that could
trigger the condition, could be useful.
 
K

Keith Thompson

James Harris said:
* the function name (as a string?)
[...]

This is available in C99 and later as __func__.

(This is an implicitly declared identifier, not a macro.)
 
M

Malcolm McLean

Although C has no support for exceptions it seems easy enough with some
programming discipline to achieve a similar effect - or at least one that
suits my purposes: basically to throw an exception at one level and catch it
higher up the call stack.

Where the exception is thrown I had in mind creating an object (i.e. a
struct) to represent some details about the exception. My question is about
what you guys would suggest to include in that object, i.e. things which are
simple in C to include and yet potentially useful. To illustrate, the call
to create the exception might be something like

excep_throw( .... );

This function would create an object to describe what was found to be wrong
and then trigger the exception handling mechanism. The mechanism is
unimportant here but what things would be good to include in the parens?

Some possibilities:



* the type of exception (an unsigned int)
* the function name (as a string?)
* __FILE__ and/or __LINE__ (if possible)
* a message string
* parameters (somehow)



Any thoughts on that? Anyone already done something similar?
A bit-shuffling function, which doesn't do IO, can fail because it runs
out of memory. Strictly, that's the only failure possible. If it fails
because of an internal programming error then by definition there can be
no correct behaviour for the program.
However it's useful to allow a "parse error" to cover functions which
allow complex language-like input, which is almost as hard to check
for correctness as to implement the function. You might also allow
a "numerical overflow" error, though mostly that's either a sign of
an internal programming error (numerical instability), or corrupt
input.

I think that just about covers bit shuffling function errors. Most
bit shuffling functions can't have any errors because they are defined
for all patterns of input bits. That's a major reason for separating
them out.

IO procedures can fail in all sorts of ways, because each hardware
device is different and has different things which can physically go
wrong with it. For filesystem type IO, basically you've got
"file not found", "file cannot be created", and a generic "IO error"
meaning that the device is reporting a read/write fail.
Then you've also got parse errors. Unlike bit shuffling functions,
where functions that do non-trivial parsing are a rarity, most procedures
that accept a file as input can fail in multiple ways because
the file format is not coherent. If input is a text file, often it's
very useful to the user to report the offending line. If it's a binary
file, really all you can do is report "file corrupt".

For non-file system IO, really the failure modes are open-ended. There's
no restriction on the number of devices which might potentially be
attached to a computer, and they can fail in many ways meaningful
to the user. Printers can run out of ink or paper, microphones can
be pushed beyond their dynamic range, radio links can become too
faint, keyboards can send unrecognised characters, and so on.
 
S

Stefan Ram

James Harris said:
Although C has no support for exceptions

7.6.2.1 The feclearexcept function
7.6.2.2 The fegetexceptflag function
7.6.2.3 The feraiseexcept function
7.6.2.4 The fesetexceptflag function
7.6.2.5 The fetestexcept function

N1570
 
J

James Kuyper

7.6.2.1 The feclearexcept function
7.6.2.2 The fegetexceptflag function
7.6.2.3 The feraiseexcept function
7.6.2.4 The fesetexceptflag function
7.6.2.5 The fetestexcept function

N1570

Those are for floating point exceptions; he's probably looking for a
more general-purpose mechanism.
 
Ad

Advertisements

K

Kaz Kylheku

While not provided by the C language most mainstream compilers offer a
vendor extension Structured Error Handling (SEH) library.

Most mainstream compilers do not have any such a thing.

I'd buy the claim that most compilers **for Win32** have this.

Structured Exception Handling is a Windows feature.
Most simple error handlers are facilitated with setjump and longjump.

setjmp and longjmp, not "jump".
 
K

Kaz Kylheku

Any thoughts on that? Anyone already done something similar?

I wrote an exception library for C more than 15 years ago.

It lives here:

http://git.savannah.gnu.org/cgit/kazlib.git/tree/except.c

And is documented here:

http://web.archive.org/web/20071015221621/http://users.footprints.net/~kaz/kazlib_doc/node161.html

It was selected for use in the Wireshark program many years ago:

https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob;f=epan/except.c;hb=HEAD

When Wireshark's packet parsers ("dissectors") encounter a garbage packet (for
instance, a truncated one), they throw an exception. (And probably there are
other uses of this in the codebase.)
 
K

Keith Thompson

Malcolm McLean said:
A bit-shuffling function, which doesn't do IO, can fail because it runs
out of memory. Strictly, that's the only failure possible. If it fails
because of an internal programming error then by definition there can be
no correct behaviour for the program.
However it's useful to allow a "parse error" to cover functions which
allow complex language-like input, which is almost as hard to check
for correctness as to implement the function. You might also allow
a "numerical overflow" error, though mostly that's either a sign of
an internal programming error (numerical instability), or corrupt
input.

I think that just about covers bit shuffling function errors. Most
bit shuffling functions can't have any errors because they are defined
for all patterns of input bits. That's a major reason for separating
them out.
sqrt(-1.0)?

IO procedures can fail in all sorts of ways, because each hardware
device is different and has different things which can physically go
wrong with it.
[...]

So you're still insisting on using your own idiosyncratic definitions
of the words "function" and "procedure"?
 
I

Ike Naar

A bit-shuffling function, which doesn't do IO, can fail because it runs
out of memory. Strictly, that's the only failure possible. If it fails
because of an internal programming error then by definition there can be
no correct behaviour for the program.

You mean it can't fail because of stack overflow, exceeded cpu-time quota,
a high temperature condition caused by a stuck fan or whatnot? Mmmm.

But let's forget about that and examine the phrase 'bit-shuffling function'
a bit more closely.

I find the phrase more than a bit confusing.
Can you provide a good definition?
It suggest that a function shuffles bits.
But what exactly do you mean by that?

Let's take a few examples.

int zero0(void)
{
return 0
};

Is this a bit-shuffling function?
If so, does it shuffle bits, and which bits does it shuffle?

Let's take another example,

#include <stdio.h>

int zero1(void)
{
FILE *hiddenlogfile = fopen("/hidden/zero.log", "a");
if (hiddenlogfile)
{
fputs("called zero()\n", hiddenlogfile);
fclose(hiddenlogfile);
}
return 0;
}

To the caller, the visible behaviour is the same as the behaviour of zero0,
but zero1 does I/O: it writes a log message to a hidden log file.
Is zero1 a bit-shuffling function?
If not, which bits were not shuffled in zero1 that were shuffled in zero0?

Another example:

#include <stdlib.h>

int zero2(void)
{
system("sleep 999");
return 0;
}

The visible behaviour to the caller is the same as the behaviour
of zero0, there is a side effect (a noticable delay), but let's assume
there's no I/O done.

Is zero2 a bit-shuffling function?
How do the bits that were shuffled in zero2 (if any) differ from the bits
that were shuffled in zero0 or zero1?

And the last example,

static int global = 0;

int zero3(void)
{
++global;
return 0;
}

It has a side effect (it increments 'global') but does not do I/O;
is zero3 a bit-shuffling function? If so, can you point out which
bits it shuffled that were not shuffled in the other functions?
 
J

Jorgen Grahn

IO procedures can fail in all sorts of ways, because each hardware
device is different and has different things which can physically go
wrong with it.
[...]

So you're still insisting on using your own idiosyncratic definitions
of the words "function" and "procedure"?

Apparently. Mr McLean: please stop -- it's confusing, no matter what
the theoretical merits of those terms are!

/Jorgen
 
Ad

Advertisements

J

Jorgen Grahn

Although C has no support for exceptions it seems easy enough with some
programming discipline to achieve a similar effect - or at least one that
suits my purposes: basically to throw an exception at one level and catch it
higher up the call stack.

The latter. I don't think you should call what you're doing
"exceptions" since that tends to imply:
- placing exception handling at different places in the call chain
- freeing of resources during stack unwinding
Where the exception is thrown I had in mind creating an object (i.e. a
struct) to represent some details about the exception. My question is about
what you guys would suggest to include in that object, i.e. things which are
simple in C to include and yet potentially useful. To illustrate, the call
to create the exception might be something like

excep_throw( .... );

This function would create an object to describe what was found to be wrong
and then trigger the exception handling mechanism. The mechanism is
unimportant here but what things would be good to include in the parens?
Some possibilities:

* the type of exception (an unsigned int)
* the function name (as a string?)
* __FILE__ and/or __LINE__ (if possible)
* a message string
* parameters (somehow)

Any thoughts on that? Anyone already done something similar?

Have you considered just calling abort()? If you're not going to
continue anyway (your program would be in a rather weird state at this
point) then aborting would give much more information for debugging
than just function and line.

/Jorgen
 
J

James Harris

Jorgen Grahn said:
The latter.

"The latter"?
I don't think you should call what you're doing
"exceptions" since that tends to imply:
- placing exception handling at different places in the call chain

Can do that.
- freeing of resources during stack unwinding

Can do that too!
Have you considered just calling abort()? If you're not going to
continue anyway (your program would be in a rather weird state at this
point) then aborting would give much more information for debugging
than just function and line.

Thanks, no, I hadn't considered calling abort() ... for at least three
reasons:

1. I didn't know about it.
2. I have a simple, if verbose, way to do what I want to do.
3. This is for bare-metal code. There is no C run-time module, no OS, no
signalling, etc.

James
 
M

Malcolm McLean

You mean it can't fail because of stack overflow, exceeded cpu-time quota,
a high temperature condition caused by a stuck fan or whatnot? Mmmm.
Stack overflow is a case of out of memory, however since you know stack usage for
a non-recursive function, its normally doesn't need to be considered.
You do have to assume that the computer is working.
But let's forget about that and examine the phrase 'bit-shuffling function'
a bit more closely.

I find the phrase more than a bit confusing.

Can you provide a good definition?
It's function which, given an input state of bits in the valid address space owned by the program,
produces anther known output state of those bits, totally defined by the input state.
(Of course in reality you only need consider a small subset of the bits, for most functions).
It suggest that a function shuffles bits.
But what exactly do you mean by that?
The bits are in one state on function entry, another state on function exit, and the function
can be replaced by any other function which produces the same bit state on output given
the same bit state on input, without affecting the correctness of the program.
Let's take a few examples.

int zero0(void)
{
return 0
};

Is this a bit-shuffling function?
If so, does it shuffle bits, and which bits does it shuffle?
If we assign the value, it
x = zero();
it shuffles x. given all 2^32 possible bit states of x on function entry, there's only one possible state
on function exit.
if we don't assign the value, it's a null shuffle. it's the function which maps input to output.
Let's take another example,

#include <stdio.h>

int zero1(void)
{

FILE *hiddenlogfile = fopen("/hidden/zero.log", "a");

if (hiddenlogfile)
{

fputs("called zero()\n", hiddenlogfile);
fclose(hiddenlogfile);
}

return 0;

}



To the caller, the visible behaviour is the same as the behaviour of zero0,
but zero1 does I/O: it writes a log message to a hidden log file.

Is zero1 a bit-shuffling function?

If not, which bits were not shuffled in zero1 that were shuffled in zero0?
It's affected the sate of something outside the program. If we replace it by the first function, the
bit state is the same, but the program is no longer correct (assuming that part of the desired
behaviour is to produce the log file).
Another example:

#include <stdlib.h>

int zero2(void)
{
system("sleep 999");
return 0;
}



The visible behaviour to the caller is the same as the behaviour
of zero0, there is a side effect (a noticable delay), but let's assume
there's no I/O done.
sleep is an exception which doesn't fit nicely in the system. You assume that results are important,
an execution time isn't part of the behaviour. In reality, all programs have some limits on
execution time.
Is zero2 a bit-shuffling function?
How do the bits that were shuffled in zero2 (if any) differ from the bits
that were shuffled in zero0 or zero1?
The don't. IO procedures also shuffle bits. But they have side effects as well.
And the last example,

static int global = 0;

int zero3(void)
{
++global;

return 0;

}
It has a side effect (it increments 'global') but does not do I/O;
is zero3 a bit-shuffling function? If so, can you point out which
bits it shuffled that were not shuffled in the other functions?
it's shuffled "global". That's why a "but shuffling function" isn't quite the same thing as a
"pure function". Part of the behaviour is to increment global, so presumably it has
partner functions which read global.

What's the point?

Bit shuffling functions.

Are inherently portable. They run on any platform with enough memory.
Are independently testable - they can be tested an proved correct independent of the status
of and hardware devices attached to the machine.
Can be idempotent - the can always be rewritten to avoid calls to other routines, with the
sole exception of memory allocation.
Have defined behaviour, assuming only that the computer is reliable.
 
M

Malcolm McLean

So you're still insisting on using your own idiosyncratic definitions
of the words "function" and "procedure"?
Im trying out "bit-shuffling function" and "IO procedure". That should strike the right balance
between inventing incomprehensible jargon and using terms which are used in other
senses.
 
K

Keith Thompson

Malcolm McLean said:
Im trying out "bit-shuffling function" and "IO procedure". That should
strike the right balance between inventing incomprehensible jargon and
using terms which are used in other senses.

Why not call them "bit-shuffling functions" and "IO functions", since C
calls all subroutines "functions"?
 
Ad

Advertisements

M

Malcolm McLean

Why not call them "bit-shuffling functions" and "IO functions", since C
calls all subroutines "functions"?
Because the analysis isn't tied to C, though it's designed for C-like languages which
operate on memory buffers.
And because "function" in normal usage means "a mapping of an input set to an
output set", or, in discrete digital terms, bit_shuffling, and "procedure" means
"a series of actions or steps in a set protocol". We don't want to get too far from
normal English usage by talking of "a function that sets the LED to flashing red".
 
K

Keith Thompson

Malcolm McLean said:
Because the analysis isn't tied to C, though it's designed for C-like
languages which operate on memory buffers.

Perhaps comp.lang.misc would be a better place to discuss it.
And because "function" in normal usage means "a mapping of an input
set to an output set", or, in discrete digital terms, bit_shuffling,
and "procedure" means "a series of actions or steps in a set
protocol". We don't want to get too far from normal English usage by
talking of "a function that sets the LED to flashing red".

In comp.lang.c, "function" means "C function".

If you find that the terminology used by the C standard (and by
C programmers) is not suited to what you're discussing, then I
suggest that what you're discussing is not suited to this newsgroup.

Or perhaps you can reframe your ideas so they're specifically
relevant to C.
 
M

Malcolm McLean

Perhaps comp.lang.misc would be a better place to discuss it.
Maybe. The idea of IO versus non-IO isn't in any way C-specific. However some
of implications are better discussed with a concrete language in mind.
In comp.lang.c, "function" means "C function".
Context is all.

If you find that the terminology used by the C standard (and by
C programmers) is not suited to what you're discussing, then I
suggest that what you're discussing is not suited to this newsgroup.
A little thing like the fact that C uses "function" to mean "subroutine"
shouldn't be hard for anyone to cope with.
Or perhaps you can reframe your ideas so they're specifically
relevant to C.
It's relevant to C because C makes it very obvious that you're bit-shuffling.
Because C makes it easy to access the actual binary bits, it's clear how a
C function can be rewritten in terms of shuffling rather than higher-level
concepts.
Also because C makes asking for memory explicit. It's obvious that a
correctly-specified and written and called bit shuffling function can only
fail if it runs out of memory. If it's passed an arrangement of bits it can't
deal with (e.g. wild pointers), it's a programming error by caller, if it
executes an illegal operation on a valid input bitset, it's an internal
programming error. But it can always run out of memory, that's a sort of
inherent problem in specifying a function in terms of expected output state
given an input state. In C, it's obvious what's happened, because malloc()
returns null. In other languages, the same underlying problem will happen,
but it's harder for the programmer to see.
Then the whole idea is ago separate out the bit-shuffling functions for the
IO procedures. C makes that easy. If you don't include stdio.h or any third party
IO-headers, you're bit shuffling. And since bit-shufling functions can be
idempotent, normally you won't need any third party headers anyway, So
you can see at a glance that the method has been applied.
With other languages, you might have to specify 'serialise" interfaces or
similar to basic classes. Whilst the idea still holds, it can become tricker and
less intuitive.
 
Ad

Advertisements

K

Keith Thompson

Malcolm McLean said:
Maybe. The idea of IO versus non-IO isn't in any way C-specific. However some
of implications are better discussed with a concrete language in mind.
Context is all.

Yes, that's my point. If you think that statement makes your case for
you, you'll have to elaborate; I'd say it argues precisely against what
you're saying.
A little thing like the fact that C uses "function" to mean "subroutine"
shouldn't be hard for anyone to cope with.

Frankly, it seems to be difficult for you to cope with. Emphasis on
"seems"; I don't really think you have difficulty understanding the
concept. You just don't put it into practice.

We have a perfectly good word, "function", with an *extremely* well
defined meaning in this context. Feel free to add meaningful
adjectives to it.

[...]
 

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

Top