Wait, Try-Catch exists in C?
Introduction
Well… yes, kind of. And it seems it has been around for a while. Why is that so unknown? Can you use it in your C code? We will answer these questions in this article.
But first… a bit of backstory.
How I got to know about it
Last week, I was at Epitech in Lyon to work on a project in a “workplace”. Some students came in the administive office to ask for help with their C project : more specifically on the minishell, a small shell program. And… they asked if they could use try-catch statements in C. All the office was like “Wait, what?”. A quick search showed that it was possible with Microsoft C. So… the student was told no, but I was intrigued. I had to know more about it.
Why Did Microsoft Introduce SEH?
Picture this: you’re writing a C program, everything is going great, and then—BOOM!—your code runs into an access violation and Windows decides your program is no longer worthy of existence. Classic C error handling (setjmp
/longjmp
) just sits there, helpless, watching your app crash and burn.
Enter Structured Exception Handling (SEH), Microsoft’s way of saying, “Hey, maybe we should try catching those nasty errors before they ruin everything.” SEH lets you handle serious issues like divide-by-zero errors, access violations, and other hardware-level disasters in a structured way.
SEH has been around since Windows NT 3.51, but it’s not as well-known as other error-handling mechanisms. Why? Because it’s a bit… weird. It’s not part of the C standard, it’s Windows-specific, and it looks like someone tried to bolt C++ exceptions onto C with duct tape and hope.
How Does It Work?
Microsoft C provides the __try
and __except
keywords to wrap risky code in a protective bubble. If something goes wrong inside the __try
block, the __except
block swoops in like a superhero to assess the damage.
Basic Example: Catching a Divide-by-Zero Error
#include <stdio.h>
#include <windows.h>
int main() {
__try {
int x = 1;
int y = 0; // Wait, are you sure?
int z = x / y; // I have a bad feeling about this...
printf("Result: %d\n", z);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
printf("I knew it. Hey, do you even know the answer to this operation?\n");
}
return 0;
}
What Just Happened?
We wrapped our dangerous code inside a __try
block.
The program attempted to divide by zero.
Windows, instead of shutting everything down, threw an exception.
The __except
block caught it and printed a friendly (yet judgmental) message.
Fine-Tuning Your Exception Handling
The __except
block can evaluate the exception and decide how to respond. Instead of blindly catching everything, you can analyze the exception code using GetExceptionCode()
:
#include <stdio.h>
#include <windows.h>
int main() {
__try {
int *p = NULL;
*p = 42; // You really bout to do it?
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH) {
printf("Say Drake, I hear you like 'em NULL.\n");
}
return 0;
}
Here, GetExceptionCode()
checks whether the error is an access violation before deciding to handle it. If it’s something else, SEH lets Windows deal with it instead.
Finally! __finally
Okay, so you’ve handled exceptions, but what about cleanup? What if you need to free memory, close files, or release system resources, regardless of whether an exception occurred?
That’s where __finally
comes in—it ensures that a block of code runs no matter what happens, just like finally in C++ and other languages.
Example: Ensuring Cleanup Happens
#include <stdio.h>
#include <windows.h>
int main() {
FILE *file = fopen("secret_article_march_3rd", "w");
if (!file) return 1;
__try {
fprintf(file, "Writing to file...\n");
int *ptr = NULL;
*ptr = 42; // Ouch
}
__finally {
printf("Closing file...\n");
fclose(file); // Always executed, even if an exception occurs.
}
return 0;
}
So… Why Is SEH So Rarely Used?
Why does no one talk about it? Here are a few reasons:
-
It’s Microsoft-Specific – SEH is a Windows-only feature, so if you’re writing portable C code, better not deal with it. Most C developers prefer cross-platform solutions that work everywhere, like
setjmp
/longjmp
or custom error-handling mechanisms. -
C++ Exceptions Took Over – C++ has a built-in exception system (try/catch) that’s more flexible and widely used. Even Microsoft itself recommends C++ exceptions over SEH for modern applications.
-
It’s a Bit… Ugly – Come on, let’s be honest,
__try
and__except
look out of place in C code. They feel like they were bolted on as an afterthought, and their syntax isn’t exactly elegant. It just feels like trying to make C++ exceptions work in C. (My fellow Epitech students know what I’m talking about if I mention “modular C”). -
Security Risks – SEH used to be a common target for buffer overflow exploits. Attackers could manipulate the exception-handling structures in memory to execute arbitrary code. Microsoft introduced SafeSEH and DEP (Data Execution Prevention) to mitigate this, but the damage to SEH’s reputation was already done.
Conclusion
SEH is Microsoft’s way of keeping your C programs from faceplanting at the first sign of trouble. It’s powerful, but it’s also niche, ugly, and somewhat obsolete in modern applications.
Still, if you’re writing low-level Windows software, SEH can be a lifesaver. Just… don’t rely on it too much.
PS: Interesting easter egg I found on x recently, about ollama. ollama by default runs on port 11434. Wonder why? 🤔. I’ll let you find out and I’ll see you next week!
11434
1143A
114MA
11AMA
1LAMA
LLAMA