2010-02-15 11 views
6

Tytuł prawie mówi wszystko, ale powtórzę pytanie ...Czy następujący program jest ściśle zgodnym programem C99?

Czy poniższy program to program ściśle zgodny z normą C99?

#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, jestem świadomy, że jeden chciałby również "wrap" free(), realloc(), strdup(), calloc() i who-knows-what-else. To nie jest pytanie. Na marginesie: kto wie co jeszcze? To są wszystkie funkcje API malloc(), które mogę wyczarować z mojej głowy. –

+2

Wystarczy wspomnieć, że ta metoda nie pomoże w używaniu malloc w żadnej zewnętrznej bibliotece. Kilka osób zapewnia alternatywne implementacje malloc, które można dodawać w czasie łącza, na przykład google pod adresem http://code.google.com/p/google-perftools/wiki/GooglePerformanceTools – gnud

Odpowiedz

11

Spójrzmy na to, co średnia C99 ma do powiedzenia na ten temat:

patrz 7.1.3, § 1, pkt 5:

Każdy identyfikator z zakresu pliku wymienione w żadnym z następujące podrozdziały [...] to zarezerwowane do użycia jako nazwa makra oraz jako identyfikator z zakresem pliku w tej samej przestrzeni nazw , jeśli dołączono którykolwiek z powiązanych nagłówków.

Po dodaniu stdlib.h, nazwa malloc jest zarezerwowana do użycia jako nazwa makra.

Ale 7.1.4, § 1 pozwala na stosowanie nazw zastrzeżonych #undef na:

Zastosowanie #undef usunąć dowolny makro definicja będzie również zapewnienie, że rzeczywista funkcja jest dalej.

To sprawia, że ​​możliwe jest ponowne #definemalloc, co powoduje zachowanie niezdefiniowane zgodnie z 7.1.3, §2:

Jeśli program [...] definiuje zastrzeżonego jako identyfikatora nazwa makra, zachowanie jest niezdefiniowane.

Dlaczego ten standard wprowadza to ograniczenie? Ponieważ inne funkcje biblioteki standardowej mogą być zaimplementowane jako makra funkcjonalne w sensie pierwotnej funkcji, więc ukrywanie deklaracji może przerwać te inne funkcje.

W praktyce powinieneś być w porządku, pod warunkiem, że twoja definicja malloc spełnia wszystkie warunki, które standard zapewnia funkcji bibliotecznej, co można osiągnąć, zawijając rzeczywiste połączenie z numerem malloc().

+0

Dobre umiejętności czytania! Jeśli nie masz nic przeciwko, czy mogę zapytać, czy możesz znaleźć tę samą odpowiedź dla C89 i rozszerzyć tutaj swoją odpowiedź? Jeśli tak, zmienię tytuł tego pytania. Takie sprawiłoby, że byłby lepszym zasobem. Zależy od Ciebie. –

+0

@Heath: sekcja 4.1.2 szkicu ANSI nie jest bardzo szczegółowa, ale mówi, że "Wszystkie zewnętrzne identyfikatory zadeklarowane w dowolnym nagłówku są zarezerwowane, niezależnie od tego, czy powiązany nagłówek jest uwzględniony."; przypis 87 zasadniczo oznacza tę samą semantykę co C99 dla tego przypadku użycia: – Christoph

+2

btw: możesz uczynić program zgodny, nie włączając 'stdlib.h' i zadeklarując' malloc() ', co jest wyraźnie dozwolone przez 7.1.4 §2 – Christoph

3

Będziemy chcieli zmienić journalling_malloc(...) z void do void * zmień komentarzy // (ponieważ są komentując swoje undef) i dodać #endif pobliżu szczytu, ale inaczej to wygląda w porządku.

+0

Dobre łapanie, dzięki. Chciałem, żeby to było coś, co się skompiluje i wprowadziłem zmianę, którą zasugerowałeś. ;) –

+3

Należy dodać, że nie trzeba zawijać wyrażenia #undef w warunku. Można #undef coś, co nie jest zdefiniowane. – DigitalRoss

+0

o człowieku dzięki za bycie moim ludzkim kompilatorem. :) –

1

Czy to działa: Tak.

Czy conformant: Nie

Według C Standard:

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

Wszystkie nazwy w standardowej bibliotece są zarezerwowane (w tym 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> 

Również ściśle Conforming program nie może określić nazwy, które są zastrzeżone dla realizacji (tj Dotyczy to nazw zastrzeżonych i idnetifiers ci, dla obecnych i tych bibliotekach zarezerwowane do wykorzystania w przyszłości).

7.1.3 (note 2) 
Specifically: 
    <quote>If the program declares or defines an identifier in a context in which 
    it is reserved or defines a reserved identifier as a macro name, 
    the behavior is undefined.</quote> 

Tak więc z definicji: definiowanie malloc() nie jest zgodne, ponieważ jest niezdefiniowanym zachowaniem (Nielegalne).

+0

Czy to oznacza, że ​​można powiedzieć, że zgodnie z C99 nazwy makr są częścią przestrzeni nazw "zwykłego identyfikatora" zdefiniowanej w sekcji 6.2.3, ust. 1, punkt 4? Pytam, ponieważ wydajesz się mówić, że nazwy makr powodują konflikt ze zwykłymi identyfikatorami. –

0

Identyfikatory makr są właściwymi nazwami, a wszystkie identyfikatory bibliotek są zabronione od aliasingu do makra bez względu na status językowy makr.

§6.10.3/7

Identyfikator bezpośrednio po define nazywany jest nazwa makra. Istnieje jedna przestrzeń nazw dla nazw makra .

§7.1.3/1

Każdy identyfikator z zakresu pliku wymienione w którymś z następujących podrozdziałów (w tym przyszłej biblioteki kierunkach) jest zarezerwowana do użycia jako nazwę makra i jako identyfikator z zakresem pliku w tej samej przestrzeni nazw, jeśli jest powiązany z którymkolwiek z powiązanych nagłówków, to jest .

§7.1.3/2

Jeżeli program stwierdza lub określa identyfikator w kontekście, w którym on jest zastrzeżone (innych niż dopuszcza 7.1.4), albo tworzy zarezerwowany identyfikator jako nazwa makra, zachowanie jest niezdefiniowane.

+0

Czy zgadzasz się z tym, że punkt 7.1.3/3 określa, że ​​można uzyskać # mallef? Jeśli tak, to czy mówisz, że język 7.1.3/1 czyni jednak niespełniającym jakiegokolwiek # definicyjnego malloc, niezależnie od jakiegokolwiek #undef? Zauważyłeś również, że nazwy makr nie mogą być "identyfikatorem z zakresem pliku", ponieważ 6.2.1/1 tworzy określone oświadczenie o statusie językowym makr. (6.2.1 jest sekcją "zakresu identyfikatora", gdzie "zakres pliku" jest zdefiniowany dla identyfikatorów bez nazwy makra.) –

+0

@Heath: 7.1.3/3 zabrania tylko rzeczy ("zachowanie jest niezdefiniowane") i odnosi się tylko do wszystkich identyfikatorów zaczynających się od podkreślenia, którego 'malloc' (przynajmniej) nie jest. Nie ma znaczenia, że ​​makra nie są identyfikatorami z zakresem pliku; 7.1.3/1 ** rezerwuje identyfikatory z zakresem pliku ** (w tym 'malloc') ** dla makr **. – Potatoswatter

+0

Ale #define nie deklaruje identyfikatora z zakresem pliku, ponieważ nie deklaruje identyfikatora. Do swojej odpowiedzi powinieneś dołączyć 7.1.3/2, tak jak ją tutaj opublikowałeś i to jest prawdziwa odpowiedź. W szczególności, gdy czytam C89/C90, jest to niezgodność z poprzednim standardem. C99 wyraźnie wspomina użycie #define, podczas gdy C89/C90 wymienia tylko deklarację zewnętrznego identyfikatora, którego nazwa makra nie jest. W każdym razie, wspomnij 7.1.3/2 tak, jak zrobiłeś w swoim usuniętym komentarzu, a ja przyjmuję twoją odpowiedź jako poprawną. Właśnie tak jest w 7.1.3/2. Widzę, że inna odpowiedź brzmi, u1st –

Powiązane problemy