2010-02-15 12 views
6

Der Titel sagt fast alles, aber ich werde die Frage wiederholen ...Ist das folgende Programm ein striktes C99-Programm?

Ist das folgende Programm ein "streng konformes Programm" unter dem C99-Standard?

#include <stdlib.h> 
/* Removing any pre-existing macro definition, in case one should exist in the implementation. 
* Seems to be allowed under 7.1.3 para 3, as malloc does not begin with _X where X is any capital letter. 
* And 7.1.4 para 1 explicitly permits #undef of such macros. 
*/ 
#ifdef malloc  
#undef malloc  
#endif    

/* Macro substitution has no impact on the external name malloc 
* which remains accessible, e.g., via "(malloc)(s)". Such use of 
* macro substitution seems enabled by 7.1.4 para 1, but not specifically 
* mentioned otherwise. 
*/ 
void * journalling_malloc(size_t size); 
#define malloc(s)  ((journalling_malloc)(s))  

int main(void) 
{ 
    return malloc(10) == NULL ? 1 : 0;  
    /* Just for the sake of expanding the 
    * macro one time, return as exit code 
    * whether the allocation was performed. 
    */ 
} 
+0

BTW, ich bin mir bewusst, dass man auch frei(), realloc(), strdup(), calloc() und who-knows-what-sonst "wrap" möchte. Das ist nicht die Frage. Nebenbei bemerkt: Wer weiß was noch? Das sind all die malloc() API, die ich aus meinem Kopf zaubern kann. –

+2

Ich möchte nur erwähnen, dass diese Methode wird nicht mit Malloc Verwendung in externen Bibliotheken helfen. Einige Leute bieten alternative malloc-Implementierungen an, die zur Linkzeit hinzugefügt werden können, zum Beispiel google http://code.google.com/p/google-perftools/wiki/GooglePerformanceTools – gnud

Antwort

11

die bei Werfen wir einen Blick, was der C99-Standard dazu zu sagen hat:

7.1.3 Siehe § 1 Satz 5:

Jeder Bezeichner mit Rahmen-Datei in einen der aufgeführten Folgende Unterklauseln [...] sind reserviert für die Verwendung als Makroname und als Bezeichner mit Dateibereich im selben Namen Leerzeichen , wenn einer der zugehörigen Header enthalten ist.

Wie Sie stdlib.h umfassen, der Name malloc ist für den Einsatz als Makronamen reserviert.

Aber 7.1.4, § 1 ermöglicht #undef auf reservierten Namen mit:

Die Verwendung von #undef jede Makrodefinition zu entfernen, wird auch dafür sorgen, dass eine eigentliche Funktion bezeichnet wird.

Dies macht es möglich, #definemalloc, re-, die nach 7.1.3 in undefinierten Verhalten führt, §2:

Wenn das Programm [...] eine reservierte Kennung als ein definiert Makroname, das Verhalten ist nicht definiert.

Warum macht der Standard diese Einschränkung? Da andere Funktionen der Standardbibliothek als funktionsähnliche Makros in Bezug auf die ursprüngliche Funktion implementiert werden können, kann das Verbergen der Deklaration diese anderen Funktionen beeinträchtigen.

In der Praxis sollten Sie in Ordnung sein, solange Ihre Definition von malloc alle Bestimmungen erfüllt, die der Standard für die Bibliotheksfunktion vorsieht, was durch Umhüllen eines tatsächlichen Aufrufs mit malloc() erreicht werden kann.

+0

Gute Lesefähigkeiten! Wenn es Ihnen nichts ausmacht, darf ich fragen, ob Sie die gleiche Antwort für C89 finden und Ihre Antwort hier ergänzen können? Wenn Sie möchten, ändere ich den Titel dieser Frage. Dies würde es zu einer besseren Ressource machen. Wie du willst. –

+0

@Heath: Abschnitt 4.1.2 des ANSI-Entwurfs ist nicht sehr detailliert, aber es besagt, dass "Alle externen Kennungen, die in einem der Header deklariert sind, reserviert sind, unabhängig davon, ob der zugehörige Header enthalten ist oder nicht."; Fußnote 87 impliziert im Wesentlichen dieselbe Semantik wie C99 für diesen Anwendungsfall – Christoph

+2

btw: Sie können das Programm so anpassen, dass Sie 'stdlib.h' nicht mit einschließen und' malloc() 'selbst deklarieren, was ausdrücklich von 7.1.4 §2 erlaubt ist – Christoph

3

Sie wollen journalling_malloc(...)void-void *, ändern, um die Kommentare ändern // (weil sie Ihre undef kommentieren out) und ein #endif in der Nähe der Spitze hinzufügen, aber ansonsten sieht es in Ordnung.

+0

Guter Fang, danke. Ich hatte gemeint, dass es etwas wäre, das kompiliert werden würde, und ich machte die von Ihnen vorgeschlagene Änderung. ;) –

+3

Ich sollte hinzufügen, dass Sie #undef nicht in eine Bedingung umbrechen müssen. Es ist in Ordnung, etwas zu definieren, das nicht definiert ist. – DigitalRoss

+0

oh man danke, dass ich mein menschlicher Compiler bin. :) –

1

Funktioniert es: Ja.

Ist es konforme: Nein

Nach dem C Standard:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Alle Namen in der Standardbibliothek sind reserviert (einschließlich malloc).

7.1.3 Reserved identifiers 
Specifically: 
    <quote>Each macro name in any of the following subclauses</quote> 
    <quote>All identifiers with external linkage in any of the 
    following subclauses</quote> 

Auch ein streng konformes Programm kann Namen nicht definieren, die für die Implementierung reserviert werden (d Diese reservierte Namen und idnetifiers enthalten, die für aktuelle Bibliotheken und die für die zukünftige Verwendung reserviert).

Also definitionsgemäß: Definieren malloc() ist nicht konform, weil es undefiniertes Verhalten (Illegal) ist.

+0

Bedeutet das, dass Sie sagen, dass Makro-Namen gemäß C99 Teil des Namensraumes "gewöhnliche Kennung" sind, der in Abschnitt 6.2.3, Absatz 1, 4. Aufzählungspunkt definiert ist? Ich frage, weil Sie anscheinend sagen, dass Makronamen mit gewöhnlichen Identifikatoren in Konflikt stehen. –

0

Makrobezeichner sind Eigennamen, und allen Bibliotheksbezeichnern jeder Art ist es untersagt, auf Makros zu aliasieren, unabhängig vom linguistischen Status von Makros.

§6.10.3/7

Die Kennung sofort folgenden wird die Definition der Makroname genannt. Es gibt einen Namensraum für Makro Namen.

§7.1.3/1

Jeder Bezeichner mit Dateigültigkeitsbereich aufgelistet in einer der folgenden Subklauseln (einschließlich der künftigen Bibliothek Richtungen) für die Verwendung als Makroname ist reserviert und als eine Kennung mit Dateibereich im gleichen Namensraum, wenn einer der zugehörigen Header enthalten ist.

§7.1.3/2

Wenn das Programm erklärt oder definiert ein Identifikator in einem Kontext, in dem es reserviert ist (außer wie durch 7.1.4 erlaubt), oder definiert Ein reservierter Bezeichner als Makroname. Das Verhalten ist nicht definiert.

+0

Stimmen Sie zu, dass 7.1.3/3 angibt, dass #undef malloc erlaubt wäre? Wenn dem so ist, sagst du, dass die Sprache von 7.1.3/1 trotzdem #meinsame #define-malloc-konforme # nondef machen würde? Außerdem haben Sie gesehen, dass Makronamen nicht "Bezeichner mit Dateibereich" sein können, da 6.2.1/1 eine spezifische Aussage über den linguistischen Status von Makros enthält. (6.2.1 ist der Bereich "Bereich des Bezeichners", wobei "Dateiumfang" für Nicht-Makro-Namen-Bezeichner definiert ist.) –

+0

@Heath: 7.1.3/3 verbietet nur Dinge ("Verhalten ist undefiniert") und bezieht sich nur auf alle Bezeichner, die mit Unterstrich beginnen, was "malloc" (zumindest) nicht ist. Es ist irrelevant, dass Makros keine Bezeichner mit Dateibereich sind; 7.1.3/1 ** reserviert Kennungen mit Dateiumfang ** (einschließlich "malloc") ** für Makros **. – Potatoswatter

+0

#define deklariert jedoch keinen Bezeichner mit Dateibereich, da er keinen Bezeichner deklariert. Sie sollten 7.1.3/2 in Ihre Antwort einbinden, als Sie es zum ersten Mal hier gepostet haben und das ist die wirkliche Antwort. Bemerkenswerterweise ist dies, wie ich in C89/C90 gelesen habe, eine Diskrepanz zum vorherigen Standard. C99 erwähnt speziell die Verwendung von #define, während C89/C90 nur die Deklaration einer externen Kennung erwähnt, die kein Makroname ist. Wie auch immer, erwähne 7.1.3/2 wie du es in deinem gelöschten Kommentar getan hast und ich akzeptiere deine Antwort als korrekt. Es ist 7.1.3/2, die es so macht. Ich sehe eine andere Antwort hat es, u1st –

Verwandte Themen