abort () Implementierung

909
deleted67

Bitte schön:

#define abort(msg) (fprintf(stderr, msg) && *((char*)0))
Antworten
2
Ich bin mir ziemlich sicher, dass andere mir zustimmen werden, aber dies ist viel zu kurz, um für eine Codeüberprüfung in Betracht zu kommen. Mark Loeser vor 9 Jahren 3
Interessant ist auch, dass Sie statt eines SIGABRT ein SIGSEGV veranlassen wollen. Mark Loeser vor 9 Jahren 1
@mark: Ich bin mir nicht so sicher, ich glaube, ein fleischiger Einliner könnte als Mindestgröße gelten. Natürlich werden die Antworten eingeschränkter sein, aber sie könnten Stil und Effizienz abdecken. winwaed vor 9 Jahren 2
Soll der Code plattformunabhängig sein? Die korrekte Implementierung kann plattformspezifisch sein. Am Ende dieser Funktion muss möglicherweise ein bestimmtes Signal oder ein anderer Systemaufruf ausgelöst werden. rwong vor 9 Jahren 0
Ich denke, der Zugriff auf den Nullzeiger führt zu undefiniertem Verhalten. Bei einigen Betriebssystemen kann es einen Wert zurückgeben, anstatt abstürzen. CodesInChaos vor 9 Jahren 0

2 Antworten auf die Frage

16
Jonathan Leffler

Nicht-Standard-Schnittstelle zur Standardfunktion

Die offensichtliche Kritik an dieser Implementierung besteht darin, dass sie eine andere Schnittstelle hat als der C-Standard:

§7.20.4.1 Die Abbruchfunktion

Zusammenfassung

#include <stdlib.h>
void abort(void);

Beschreibung

Die abortFunktion bewirkt, dass ein abnormaler Programmabbruch auftritt, es sei denn, das Signal SIGABRTwird abgefangen und der Signalhandler kehrt nicht zurück. Ob offene Streams mit ungeschriebenen gepufferten Daten geleert, offene Streams geschlossen oder temporäre Dateien entfernt werden, ist implementierungsdefiniert. Eine implementierungsdefinierte Form des Status "erfolglos" wird mit Hilfe des Funktionsaufrufs an die Host-Umgebung zurückgegeben raise(SIGABRT).

Kehrt zurück

Die Abbruchfunktion kehrt nicht zu ihrem Anrufer zurück.

Unzuverlässige Implementierung von "Absturz"

Es gab Systeme, bekanntermaßen die DEC VAX, bei denen der Zugriff auf den Speicher unter Adresse 0 keine Probleme verursachte (bis die auf der VAX geschriebenen Programme auf andere Plattformen portiert wurden, die abgebrochen hatten).

Das Referenzieren eines Nullzeigers ist ein undefiniertes Verhalten. Dies bedeutet, dass alles passieren kann, einschließlich "kein Absturz".

Nitpicks in der Umsetzung

Wenn aus irgendeinem Grund fprintf()0 zurückgegeben wird, bricht Ihr Programm nicht ab. Zum Beispiel:

abort("");

bricht nicht ab. Es ist auch gefährlich, die Zeichenfolge als Formatzeichenfolge zu verwenden. du solltest benutzen:

#define abort(msg) (fprintf(stderr, "%s\n", msg) && *((char*)0))

Es ist besser, einen Kommaoperator anstelle von zu verwenden &&:

#define abort(msg) (fprintf(stderr, "%s\n", msg), raise(SIGABRT))

Da die Standardbibliothek ein Makro definiert haben könnte abort(), sollten Sie #undefes vor der Definition selbst festlegen.

vielleicht lieber "fputs"? Ben Voigt vor 8 Jahren 0
Ein Grund, `fputs () 'nicht zu verwenden, besteht darin, dass der Zeichenfolge keine Newline hinzugefügt wird (im Gegensatz zu' put ()` -, die jedoch in stdout statt stderr geschrieben wird), sodass Sie sie zweimal aufrufen müssen mit der Benutzerzeichenfolge und einmal mit dem Zeilenumbruch. Es scheint einfacher zu sein, `fprintf ()` einmal aufzurufen. Jonathan Leffler vor 8 Jahren 0
@Johnathan: Ich bin mir ziemlich sicher, dass `fputs 'gefolgt von` fputc (stderr,' \ n ') `(und dann Flush) viel schneller als` fprintf` wäre. Wenn Sie einen Fehler melden, möchten Sie in der Regel die trivialsten Funktionen verwenden (damit Daten nicht beschädigt werden), und "fputs" und "fputc" sind viel einfacher als "fprintf". Ben Voigt vor 8 Jahren 0
5
Martin York

Meine Kritik ist, dass Sie versuchen, durch einen Absturz abzubrechen:

*((char*)0))

Dies führt zu undefiniertem Verhalten. Es führt nicht notwendigerweise zu einem Absturz (oder einer Beendigung).

Wenn Sie das Abbruchsignal erhöhen möchten, tun Sie dies explizit:

raise(SIGABRT)

Außerdem definieren Sie eine Systemmethode mit #define neu (ich bin relativ sicher, dass dies nicht zulässig ist und undefiniertes Verhalten verursacht, obwohl ich Kapitel und Vers nicht zitieren kann).

#define abort(msg) 

Auf diese Weise müssen Sie auch die gesamte Quelle durchsuchen, um die aktuelle Abbruchnutzung zu ermitteln. Da dies mit der neuen Verwendung kollidieren kann (oder wird der Pre-Prozessor darüber intelligent sein. Die Tatsache, dass ich die Frage stelle, sollte Sie beunruhigen lassen, die Antwort ganz zu schweigen).

Definieren Sie Ihre eigene Funktion mit einem etwas anderen Namen (damit können Sie den Systemabbruch auch aufrufen).

#define abortWithMsg(msg) do { fprintf(stderr, msg); abort(); } while (false)