Ok, ich konnte nicht widerstehen, darauf zu antworten. Lassen Sie mich zunächst sagen, dass ich es nicht für eine gute Idee halte, dies in C zu simulieren, da es für C wirklich ein Fremdwort ist.
Wir können verwenden die Prä - Prozessor und lokalen Stack - Variablen missbrauchen Verwendung eine eingeschränkte Version von C ++ try / throw / catch zu geben.
Version 1 (lokaler Gültigkeitsbereich wirft)
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) __HadError=true;goto ExitJmp;
Version 1 ist nur ein lokaler Wurf (kann den Funktionsumfang nicht verlassen). Es hängt von der Fähigkeit von C99 ab, Variablen im Code zu deklarieren (es sollte in C89 funktionieren, wenn der Versuch als erstes in der Funktion ist).
Diese Funktion erstellt nur eine lokale Variable, damit sie weiß, ob ein Fehler aufgetreten ist, und springt mit einem goto zum catch-Block.
Beispielsweise:
#include <stdio.h>
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) __HadError=true;goto ExitJmp;
int main(void)
{
try
{
printf("One\n");
throw();
printf("Two\n");
}
catch(...)
{
printf("Error\n");
}
return 0;
}
Das funktioniert wie folgt:
int main(void)
{
bool HadError=false;
{
printf("One\n");
HadError=true;
goto ExitJmp;
printf("Two\n");
}
ExitJmp:
if(HadError)
{
printf("Error\n");
}
return 0;
}
Version 2 (Scope Jumping)
#include <stdbool.h>
#include <setjmp.h>
jmp_buf *g__ActiveBuf;
#define try jmp_buf __LocalJmpBuff;jmp_buf *__OldActiveBuf=g__ActiveBuf;bool __WasThrown=false;g__ActiveBuf=&__LocalJmpBuff;if(setjmp(__LocalJmpBuff)){__WasThrown=true;}else
#define catch(x) g__ActiveBuf=__OldActiveBuf;if(__WasThrown)
#define throw(x) longjmp(*g__ActiveBuf,1);
Version 2 ist viel komplexer, funktioniert aber grundsätzlich genauso. Es wird ein langer Sprung von der aktuellen Funktion zum try-Block verwendet. Der try-Block verwendet dann ein if / else, um den Codeblock zum catch-Block zu überspringen, der die lokale Variable überprüft, um festzustellen, ob sie abfangen soll.
Das Beispiel wurde erneut erweitert:
jmp_buf *g_ActiveBuf;
int main(void)
{
jmp_buf LocalJmpBuff;
jmp_buf *OldActiveBuf=g_ActiveBuf;
bool WasThrown=false;
g_ActiveBuf=&LocalJmpBuff;
if(setjmp(LocalJmpBuff))
{
WasThrown=true;
}
else
{
printf("One\n");
longjmp(*g_ActiveBuf,1);
printf("Two\n");
}
g_ActiveBuf=OldActiveBuf;
if(WasThrown)
{
printf("Error\n");
}
return 0;
}
Dies verwendet einen globalen Zeiger, damit longjmp () weiß, welcher Versuch zuletzt ausgeführt wurde. Wir verwenden den Stapel, damit untergeordnete Funktionen auch einen Try / Catch-Block haben können.
Die Verwendung dieses Codes hat eine Reihe von Nachteilen (ist aber eine lustige mentale Übung):
- Der zugewiesene Speicher wird nicht freigegeben, da keine Dekonstruktoren aufgerufen werden.
- Sie können nicht mehr als 1 Versuch / Fang in einem Bereich haben (keine Verschachtelung)
- Sie können keine Ausnahmen oder andere Daten wie in C ++ auslösen
- Überhaupt nicht threadsicher
- Sie richten andere Programmierer für einen Fehler ein, da sie den Hack wahrscheinlich nicht bemerken und versuchen, sie wie C ++ - Try / Catch-Blöcke zu verwenden.