CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
Exception Handling

Data Structures

struct  ExceptionInfo
 

Macros

#define ptThrow(code, msg)   _ptry_throw(code, msg)
 
#define ptRethrow   _ptry_throw(_ptry_exc.code, _ptry_exc.msg)
 
#define ptTry
 
#define ptFinally
 
#define ptCatch
 
#define ptCode   _ptry_exc.code
 
#define ptMsg   _ptry_exc.msg
 

Typedefs

typedef struct ExceptionInfo ExceptionInfo
 
typedef int(* ptUnhandledHandler) (ExceptionInfo *einfo)
 

Functions

void ptRegisterUnhandled (ptUnhandledHandler handler)
 
void ptUnregisterUnhandled (ptUnhandledHandler handler)
 

Detailed Description

Advanced Feature: Exception handling with try/catch/finally semantics.

Provides exception handling built on protected blocks, allowing errors to propagate up the call stack with automatic cleanup. However, this system has important semantic differences from exception handling in languages like C++ or Java.

Performance Warning:

Exception handling inherits all the performance costs of protected blocks:

Critical Semantic Differences:

  1. ptCatch blocks ALWAYS execute, even when no exception occurs:
    • Check ptCode to determine if an exception actually happened
    • ptCode == 0 means no exception
  2. No automatic exception filtering:
    • ptCatch catches ALL exceptions
    • Must manually check ptCode and use ptRethrow for selective handling
  3. Exception messages MUST be static string literals:
    • Cannot use stack-allocated or heap-allocated strings
    • Messages are stored by pointer, not copied
  4. Cannot mix pblocks and exceptions:
    • Once using ptTry/ptCatch, must use them consistently
    • PBLOCK_AFTER labels are skipped during exception processing
    • Using ptThrow inside a non-ptTry pblock causes incorrect flow

When to Use:

When NOT to Use:

Example:

resource1 = acquire1();
if (!resource1) ptThrow(ERR_RESOURCE, "Failed to acquire resource1");
resource2 = acquire2();
if (!resource2) ptThrow(ERR_RESOURCE, "Failed to acquire resource2");
processData();
}
// ALWAYS runs, even without exception
if (ptCode) {
// Exception occurred
logError("Exception %d: %s", ptCode, ptMsg);
// Selective handling
if (ptCode == ERR_FATAL) {
ptRethrow; // Let caller handle fatal errors
}
}
// Cleanup
if (resource2) release2(resource2);
if (resource1) release1(resource1);
}
#define ptRethrow
Definition ptry.h:273
#define ptMsg
Definition ptry.h:451
#define ptTry
Definition ptry.h:307
#define ptCode
Definition ptry.h:431
#define ptThrow(code, msg)
Definition ptry.h:237
#define ptCatch
Definition ptry.h:406

Macro Definition Documentation

◆ ptCatch

#define ptCatch
Value:
_ptry_after_block \
_blkAfter(_ptry_clear())

ptCatch { }

Exception handler block that ALWAYS executes and stops exception propagation.

The ptCatch block MUST immediately follow a ptTry block. It is similar to ptFinally but with a critical difference: ptCatch stops exception propagation by default.

Critical Semantic Differences from C++/Java:

  1. ptCatch ALWAYS executes, even when no exception occurred:
    • Check ptCode to determine if an exception happened
    • ptCode == 0 means normal execution (no exception)
    • ptCode != 0 means an exception occurred
  2. No automatic filtering - catches ALL exceptions:
    • Must manually check ptCode to filter exception types
    • Use ptRethrow to propagate exceptions you don't handle
  3. Stops exception propagation by default:
    • Exception processing ends after this block unless you ptRethrow
    • Use ptFinally if you want automatic propagation

Example:

doWork();
}
// ALWAYS runs, check ptCode to see if exception occurred
if (ptCode) {
printf("Exception %d: %s\n", ptCode, ptMsg);
// Selective handling
if (ptCode == ERR_FATAL) {
ptRethrow; // Let caller handle
}
// Other errors handled locally
}
// Cleanup runs whether exception occurred or not
cleanup();
}
Note
Exception is cleared after this block - use ptRethrow to propagate
See also
ptTry, ptFinally, ptCode, ptMsg, ptRethrow

Definition at line 406 of file ptry.h.

◆ ptCode

#define ptCode   _ptry_exc.code

ptCode

The exception code of the currently active exception, or 0 if there is none.

Use inside ptCatch or ptFinally blocks to check if an exception occurred and to determine the exception type.

Example:

if (ptCode == 0) {
// No exception - normal execution
} else if (ptCode == ERR_IO) {
// Handle I/O errors
} else {
// Handle other errors
}
}
See also
ptMsg, ptCatch, ptFinally

Definition at line 431 of file ptry.h.

◆ ptFinally

#define ptFinally
Value:
_ptry_after_block \
/* finally blocks end in an implicit rethrow if there is an active exception */ \
_blkAfter(_ptry_exc.code ? ptRethrow : nop_stmt)
#define nop_stmt
Definition unused.h:44
int code
Application-specific exception code.
Definition ptry.h:89

ptFinally { }

Cleanup block that executes after a ptTry, whether an exception occurred or not.

The ptFinally block MUST immediately follow a ptTry block. It executes after the ptTry completes or an exception occurs. If an exception occurred, it is automatically re-thrown after the ptFinally block completes, propagating to the caller's handler.

Use ptFinally when:

  • You need guaranteed cleanup but don't want to handle the exception
  • The exception should propagate to the caller after cleanup

Example:

file = fopen("data.txt", "r");
if (!file) ptThrow(ERR_IO, "Cannot open file");
processFile(file);
}
// Always runs, exception continues propagating upward
if (file) fclose(file);
}
#define ptFinally
Definition ptry.h:356
Note
If an exception occurred, it is implicitly re-thrown after this block
See also
ptTry, ptCatch, ptCode, ptMsg

Definition at line 356 of file ptry.h.

◆ ptMsg

#define ptMsg   _ptry_exc.msg

ptMsg

The exception message of the currently active exception, or NULL if there is none.

Points to the static string literal passed to ptThrow(). Use inside ptCatch or ptFinally blocks to access the error message.

Example:

if (ptCode) {
fprintf(stderr, "Error %d: %s\n", ptCode, ptMsg);
}
}
Warning
This is a pointer to the original string literal, not a copy
See also
ptCode, ptCatch, ptFinally

Definition at line 451 of file ptry.h.

◆ ptRethrow

#define ptRethrow   _ptry_throw(_ptry_exc.code, _ptry_exc.msg)

ptRethrow

Re-throws the currently active exception to a handler further up the call stack.

Used inside a ptCatch block to propagate an exception after performing local cleanup or logging. This is the mechanism for selective exception handling - catch specific exception codes locally and rethrow others.

Example:

doWork();
}
if (ptCode) {
logError("Exception %d: %s", ptCode, ptMsg);
// Handle I/O errors locally
if (ptCode == ERR_IO) {
useDefaultData();
} else {
// Let caller handle other errors
}
}
}
Note
Only valid inside a ptCatch block while ptCode is non-zero
See also
ptThrow, ptCatch, ptCode

Definition at line 273 of file ptry.h.

◆ ptThrow

#define ptThrow (   code,
  msg 
)    _ptry_throw(code, msg)

ptThrow(code, msg)

Throws an exception to be caught by a ptCatch or ptFinally block up the call stack.

An exception consists of a numeric code (application-defined) and a message. Control transfers immediately to the nearest ptCatch/ptFinally block, unwinding the stack and executing any cleanup code along the way.

Parameters
codeApplication-specific numeric exception code (integer constant)
msgException message - MUST be a static string literal

Critical Requirements:

Example:

#define ERR_IO 100
#define ERR_MEMORY 101
FILE *f = fopen("data.txt", "r");
if (!f) ptThrow(ERR_IO, "Failed to open data.txt"); // OK - string literal
void *mem = malloc(size);
if (!mem) ptThrow(ERR_MEMORY, "Out of memory"); // OK - string literal
Note
In debug builds, file and line number are automatically captured
See also
ptCatch, ptFinally, ptRethrow

Definition at line 237 of file ptry.h.

◆ ptTry

#define ptTry
Value:
/* phase 0 is the try, phase 1 is the catch/finally */ \
for (unsigned _ptry_phase = 0; _ptry_phase < 2; ++_ptry_phase) \
/* try phase */ \
if (!_ptry_phase) \
/* push the current pblock jump target to the exception handler stack */ \
/* this will cause it to be entered through the switch label */ \
_blkBefore(_ptry_push(_pblock_unwind_top)) \
do
#define pblock
Definition pblock.h:124

ptTry { }

Begins a try block for exception handling.

If an exception occurs inside the ptTry block, execution transfers to the immediately following ptCatch or ptFinally block. One or the other is REQUIRED - a ptTry without a matching ptCatch or ptFinally is a compile error.

Key Differences from C++/Java:

  • Must be immediately followed by ptCatch or ptFinally (no multiple catch blocks)
  • No automatic exception type filtering
  • return is not allowed within the try block

If an exception is not caught anywhere in the call stack, the unhandled exception handler is invoked (default: terminates the program with an error).

Example:

resource = acquire();
if (!resource) ptThrow(ERR_RESOURCE, "Acquisition failed");
useResource(resource);
}
if (resource) release(resource);
}
Note
Inherits all performance costs of protected blocks
Warning
Cannot mix with plain pblocks in the same call graph
See also
ptCatch, ptFinally, ptThrow

Definition at line 307 of file ptry.h.

Typedef Documentation

◆ ExceptionInfo

typedef struct ExceptionInfo ExceptionInfo

Exception information structure.

Contains details about an exception that is being thrown or is currently active. This is stored in thread-local storage during exception processing.

◆ ptUnhandledHandler

typedef int(* ptUnhandledHandler) (ExceptionInfo *einfo)

Handler function for uncaught exceptions.

Parameters
einfoInformation about the uncaught exception
Returns
0 to abort the program, 1 to resume execution after the exception point

Definition at line 105 of file ptry.h.

Function Documentation

◆ ptRegisterUnhandled()

void ptRegisterUnhandled ( ptUnhandledHandler  handler)

Registers a handler for uncaught exceptions.

The handler is called when an exception is thrown with no matching ptCatch block up the call stack. This is a last-resort mechanism for error reporting or recovery.

Parameters
handlerCallback function that receives the exception information. Return 0 to abort the program, or 1 to resume execution.

If multiple handlers are registered, they must ALL return 1 for execution to resume. Execution resumes after the outermost ptFinally block, or immediately after the throw if no ptTry blocks exist.

Example:

int myHandler(ExceptionInfo *einfo) {
fprintf(stderr, "Uncaught exception %d: %s\n", einfo->code, einfo->msg);
return 0; // Abort
}
void ptRegisterUnhandled(ptUnhandledHandler handler)
const char * msg
Exception message - MUST be a static string literal.
Definition ptry.h:90

◆ ptUnregisterUnhandled()

void ptUnregisterUnhandled ( ptUnhandledHandler  handler)

Unregisters a previously registered handler for uncaught exceptions.

Parameters
handlerThe handler function to remove