exceptions4c-lite 1.0
Lightweight exception handling for C
Loading...
Searching...
No Matches
exceptions4c-lite.h File Reference

Really lightweight exception handling for C. More...

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

Data Structures

struct  e4c_exception
 Represents a specific occurrence of an exceptional situation in a program. More...
 

Macros

#define EXCEPTIONS4C_LITE   1
 Returns the major version number of this library.
 
#define EXCEPTIONS4C_MAX_BLOCKS   32
 Determines the maximum number of TRY blocks that can be nested.
 
#define EXCEPTIONS4C_MAX_LENGTH   256
 Determines the maximum length of an exception message, in characters.
 
#define EXCEPTIONS4C_PANIC
 Determines what needs to be done in the event of too many nested TRY blocks.
 
#define EXCEPTIONS4C_TERMINATE
 Determines what needs to be done in the event of an uncaught exception.
 
#define TRY
 Introduces a block of code that may throw exceptions during execution.
 
#define CATCH(exception_type)
 Introduces a block of code that handles exceptions thrown by a preceding TRY block.
 
#define CATCH_ALL
 Introduces a block of code that handles any exception thrown by a preceding TRY block, regardless of its type.
 
#define FINALLY
 Introduces a block of code that is executed after a TRY block, regardless of whether an exception was thrown or not.
 
#define THROW(exception_type, error_message)
 Throws an exception, interrupting the normal flow of execution.
 
#define THROWF(exception_type, format, ...)
 Throws an exception with a formatted error message.
 
#define EXCEPTION
 Retrieves the last exception that was thrown.
 
#define EXCEPTION_IS_UNCAUGHT
 Determines whether the thrown exception was not caught.
 
#define EXCEPTION_PRINT
 Prints the current exception to standard error output and flushes it.
 
#define EXCEPTION_RETHROW
 Throws the current exception again.
 

Typedefs

typedef const char * e4c_exception_type
 Represents a category of problematic situations in a program.
 

Variables

struct e4c_context exceptions4c
 Contains the current status of exceptions.
 

Detailed Description

Really lightweight exception handling for C.

This library consists of one header file only. All you need to do is copy exceptions4c-lite.h into your project, include it, and define a global variable exceptions4c.

struct e4c_context exceptions4c = {0};
Really lightweight exception handling for C.
struct e4c_context exceptions4c
Contains the current status of exceptions.

Since it's a header-only library, there is no library code to link against.

Remarks
This is the lightweight version of exceptions4c. You may also want to try the full version of the library on GitHub.
Version
1.0.0
Author
Guillermo Calvo
See also
For more information, visit the project on GitHub

Macro Definition Documentation

◆ EXCEPTIONS4C_LITE

#define EXCEPTIONS4C_LITE   1

Returns the major version number of this library.

◆ EXCEPTIONS4C_MAX_BLOCKS

#define EXCEPTIONS4C_MAX_BLOCKS   32

Determines the maximum number of TRY blocks that can be nested.

The total number of blocks are preallocated inside the global variable that contains the current status of exceptions.

Note
You MAY define this macro with a different value.

◆ EXCEPTIONS4C_MAX_LENGTH

#define EXCEPTIONS4C_MAX_LENGTH   256

Determines the maximum length of an exception message, in characters.

The total number of characters are preallocated inside each exception object.

Note
You MAY define this macro with a different value.

◆ EXCEPTIONS4C_PANIC

#define EXCEPTIONS4C_PANIC
Value:
(void) fprintf(stderr, "\n[exceptions4c-lite]: " \
"Too many TRY blocks nested.\n at %s:%d\n", __FILE__, __LINE__), \
(void) fflush(stderr), \
abort()

Determines what needs to be done in the event of too many nested TRY blocks.

Note
You MAY define this macro with a different value.

◆ EXCEPTIONS4C_TERMINATE

#define EXCEPTIONS4C_TERMINATE
Value:
(void) EXCEPTION_PRINT, \
(void) fflush(stderr), \
exit(EXIT_FAILURE)
#define EXCEPTION_PRINT
Prints the current exception to standard error output and flushes it.
Definition exceptions4c-lite.h:521

Determines what needs to be done in the event of an uncaught exception.

Note
You MAY define this macro with a different value.

◆ TRY

#define TRY
Value:
\
for ( \
&& ((void) (EXCEPTIONS4C_PANIC), 0)), \
exceptions4c.blocks++, \
EXCEPTION_BLOCK.stage = EXCEPTION_BLOCK.uncaught = 0, \
(void) setjmp(EXCEPTION_BLOCK.jump); \
\
EXCEPTION_BLOCK_RANGE_CHECK && (++EXCEPTION_BLOCK.stage < 4 \
|| (exceptions4c.block[--exceptions4c.blocks].uncaught \
&& ((void) (exceptions4c.blocks > 0 && (EXCEPTION_PROPAGATE, 0)), \
(void) (EXCEPTIONS4C_TERMINATE), 0))); \
) \
if (EXCEPTION_BLOCK.stage == 1)
#define EXCEPTIONS4C_PANIC
Determines what needs to be done in the event of too many nested TRY blocks.
Definition exceptions4c-lite.h:104
#define EXCEPTIONS4C_MAX_BLOCKS
Determines the maximum number of TRY blocks that can be nested.
Definition exceptions4c-lite.h:75
#define EXCEPTIONS4C_TERMINATE
Determines what needs to be done in the event of an uncaught exception.
Definition exceptions4c-lite.h:137

Introduces a block of code that may throw exceptions during execution.

The TRY block is used to define a section of code where exceptions MAY occur. It allows you to handle exceptions gracefully using other blocks that follow it. If an exception occurs, control is transferred to the appropriate block.

A single TRY block MAY be followed by:

  1. One or more CATCH blocks to handle specific types of exceptions.
  2. Optionally, one CATCH_ALL block to handle all exception types (if present, it MUST appear after all CATCH blocks).
  3. Optionally, one FINALLY block to execute cleanup code, regardless of whether an exception was thrown or caught.
Attention
These blocks MUST NOT be exited through any of: goto, break, continue, or return.
Important
Local variables in the function containing the TRY block MUST be volatile because these blocks invoke setjump and their values would be indeterminate if they had been changed since the invocation.

Example:

/* Returns the status of a pet by id */
pet_status get_pet_status(int id) {
pet_status status = ERROR;
TRY {
status = pet_find(id)->status;
}
return status;
}
See also
CATCH
CATCH_ALL
FINALLY

◆ CATCH

#define CATCH ( exception_type)
Value:
\
&& EXCEPTION_BLOCK.stage == 2 \
&& (exception_type) == EXCEPTION.type \
&& (EXCEPTION_BLOCK.uncaught = 0, 1))
#define EXCEPTION
Retrieves the last exception that was thrown.
Definition exceptions4c-lite.h:483
#define EXCEPTION_IS_UNCAUGHT
Determines whether the thrown exception was not caught.
Definition exceptions4c-lite.h:510

Introduces a block of code that handles exceptions thrown by a preceding TRY block.

Use this macro to to handle a specific type of exceptions when they occur.

If type is equal to the type of the thrown exception, then this block will be used to handle it.

One or more CATCH blocks MAY follow a TRY block. If type doesn't match the thrown exception, then this block will be ignored, and the exception MAY be caught by the following CATCH or CATCH_ALL blocks.

Attention
These blocks MUST NOT be exited through any of: goto, break, continue, or return.
Parameters
exception_typeThe type of exception to catch.

Example:

/* Returns the status of a pet by id */
pet_status get_pet_status(int id) {
pet_status status = ERROR;
TRY {
status = pet_find(id)->status;
} CATCH (PET_NOT_FOUND) {
status = UNKNOWN;
} CATCH (NOT_ENOUGH_MEMORY) {
abort();
}
return status;
}
See also
TRY
CATCH_ALL

◆ CATCH_ALL

#define CATCH_ALL
Value:
\
&& EXCEPTION_BLOCK.stage == 2 \
&& (EXCEPTION_BLOCK.uncaught = 0, 1))

Introduces a block of code that handles any exception thrown by a preceding TRY block, regardless of its type.

The CATCH_ALL block works like a general CATCH block that does not require specifying the type of exception to handle. It MAY be used as a fallback for catching all exceptions, including those not explicitly declared in other CATCH blocks.

Only one CATCH_ALL block is allowed per TRY block, and it MUST appear after all type-specific CATCH blocks if any are present.

Remarks
Using a CATCH_ALL block is useful for logging, debugging, or handling unexpected exceptions that don't fit into specific categories. However, specific CATCH blocks SHOULD be used whenever possible to maintain clarity and precise control over exception handling.
Attention
These blocks MUST NOT be exited through any of: goto, break, continue, or return.

Example:

/* Returns the status of a pet by id */
pet_status get_pet_status(int id) {
pet_status status = ERROR;
TRY {
status = pet_find(id)->status;
status = UNKNOWN;
}
return status;
}
See also
TRY
CATCH

◆ FINALLY

#define FINALLY
Value:
\
else if (EXCEPTION_BLOCK_RANGE_CHECK && EXCEPTION_BLOCK.stage == 3)

Introduces a block of code that is executed after a TRY block, regardless of whether an exception was thrown or not.

Use this macro to run a block, no matter whether an exception happens or not.

A FINALLY block MUST be preceded by a single TRY block, after all the accompanying CATCH and CATCH_ALL blocks (if any). Only one FINALLY block is allowed per block.

Attention
These blocks MUST NOT be exited through any of: goto, break, continue, or return.
Remarks
This macro SHOULD be used to release resources, close files, or perform cleanup tasks.

Example:

/* Returns the status of a pet by id */
pet_status get_pet_status(int id) {
pet_status status = ERROR;
Pet pet = NULL;
TRY {
pet = pet_find(id);
status = pet->status;
} CATCH (PET_NOT_FOUND) {
status = UNKNOWN;
} FINALLY {
pet_free(pet);
}
return status;
}
See also
TRY

◆ THROW

#define THROW ( exception_type,
error_message )
Value:
\
(EXCEPTION.type = (exception_type), EXCEPTION.name = (error_message), \
(void) sprintf(EXCEPTION.message, "%.*s", \
EXCEPTION.name ? EXCEPTION.name : EXCEPTION.type), \
EXCEPTION.name = #exception_type, EXCEPTION_RETHROW)
#define EXCEPTIONS4C_MAX_LENGTH
Determines the maximum length of an exception message, in characters.
Definition exceptions4c-lite.h:90
#define EXCEPTION_RETHROW
Throws the current exception again.
Definition exceptions4c-lite.h:551

Throws an exception, interrupting the normal flow of execution.

THROW is used within a TRY block, a CATCH block, or any other function to signal that an error has occurred. The thrown exception will be of the specified type, and it MAY be handled by a preceding CATCH block.

If a thrown exception is not handled by any of the CATCH blocks in the current function, it propagates up the call stack to the function that called the current function. This continues until the exception is either handled by a CATCH block higher in the stack, or it reaches the top level of the program. If no CATCH block handles the exception, the program terminates and an error message is printed to the console.

Remarks
The error message will be copied as it is into the thrown EXCEPTION. To use a formatted error message, use THROWF instead. If no message is specified, then the default message for the exception type will be used.
Important
Control never returns to the THROW point.

Example:

/* Returns a pet by id */
Pet pet_find(int id) {
Pet pet = pet_clone(id);
if (!pet) {
THROW(PET_NOT_FOUND, "Oh no");
}
return pet;
}
Parameters
exception_typeThe type of the exception to throw.
error_messageThe error message.
See also
THROWF
CATCH
CATCH_ALL

◆ THROWF

#define THROWF ( exception_type,
format,
... )
Value:
\
(EXCEPTION.type = (exception_type), EXCEPTION.name = #exception_type, \
(void) snprintf(EXCEPTION.message, (EXCEPTIONS4C_MAX_LENGTH), \
(format), __VA_ARGS__), EXCEPTION_RETHROW)

Throws an exception with a formatted error message.

This macro works just like THROW, but it allows you to format the error message, just as you would with printf.

Important
Control never returns to the THROW point.

Example:

/* Returns a pet by id */
Pet pet_find(int id) {
Pet pet = pet_clone(id);
if (!pet) {
THROW(PET_NOT_FOUND, "Oh no");
}
return pet;
}
Parameters
exception_typeThe type of the exception to throw.
formatThe error message.
...A list of arguments that will be formatted according to format.
See also
THROW
CATCH
CATCH_ALL

◆ EXCEPTION

#define EXCEPTION
Value:
\
exceptions4c.thrown

Retrieves the last exception that was thrown.

Remarks
This macro SHOULD be used in the body of a CATCH or CATCH_ALL block to inspect the exception being handled. It MAY also be used in the body of a FINALLY block to determine if an exception was thrown in the corresponding TRY block, or during the execution of a CATCH or CATCH_ALL block.

Example:

/* Returns the status of a pet by id */
pet_status get_pet_status(int id) {
pet_status status = ERROR;
TRY {
status = pet_find(id)->status;
if (EXCEPTION.type == NOT_ENOUGH_MEMORY) {
abort();
}
status = UNKNOWN;
}
return status;
}
Returns
The last exception that was thrown.
See also
e4c_exception
THROW
CATCH
FINALLY
EXCEPTION_IS_UNCAUGHT

◆ EXCEPTION_IS_UNCAUGHT

#define EXCEPTION_IS_UNCAUGHT
Value:
\
(EXCEPTION_BLOCK_RANGE_CHECK && EXCEPTION_BLOCK.uncaught)

Determines whether the thrown exception was not caught.

An exception is considered "uncaught" if no matching CATCH or CATCH_ALL block has been executed for it. In other words, this macro evaluates to a truthy value if the exception has bypassed all specific exception-handling logic and is propagating further. And it evaluates to a falsy value if no exception was thrown in the TRY block, or if an exception was successfully caught.

Remarks
This macro SHOULD be used exclusively in the body of a FINALLY block to check whether an exception thrown during the TRY block has propagated past all CATCH and CATCH_ALL blocks without being handled.

Example:

int main(int argc, char * argv[]) {
TRY {
process_data(argc, argv);
} FINALLY {
fprintf(stderr, "Fatal error while processing data.\n");
} else {
fprintf(stdout, "Data processed successfully.\n");
}
}
return EXIT_SUCCESS;
}
Returns
A truthy value if the current exception (if any) has not yet been handled by any CATCH or CATCH_ALL block; a falsy value otherwise.
See also
FINALLY
EXCEPTION

◆ EXCEPTION_PRINT

#define EXCEPTION_PRINT
Value:
\
(fprintf(stderr, "\n%s: %s\n at %s:%d\n", \
EXCEPTION.name, EXCEPTION.message, EXCEPTION.file, EXCEPTION.line))

Prints the current exception to standard error output and flushes it.

See also
EXCEPTION

◆ EXCEPTION_RETHROW

#define EXCEPTION_RETHROW
Value:
\
(EXCEPTION.file = __FILE__, EXCEPTION.line = __LINE__, \
(exceptions4c.blocks <= 0 && ((void) (EXCEPTIONS4C_TERMINATE), 0)), \
EXCEPTION_PROPAGATE)

Throws the current exception again.

Remarks
This macro SHOULD be used in the body of CATCH or CATCH_ALL blocks to throw the exception that is currently being handled.
See also
CATCH
CATCH_ALL

Typedef Documentation

◆ e4c_exception_type

typedef const char* e4c_exception_type

Represents a category of problematic situations in a program.

Defines a kind of error or exceptional condition that a program MAY want to THROW and CATCH. It serves as a way to group related issues that share common characteristics.

Exception types SHOULD be defined as const.

const e4c_exception_type NOT_ENOUGH_MEMORY = "Not enough memory";
const e4c_exception_type PET_NOT_FOUND = "Pet not found";
See also
THROW
CATCH

Variable Documentation

◆ exceptions4c

struct e4c_context exceptions4c
extern

Contains the current status of exceptions.

You MUST define this global variable for your program.

struct e4c_context exceptions4c = {0};