2010-01-26 5 views
5

Ich habe den folgenden C99-Code geschrieben und habe mich über die struct-Deklaration gewundert. Darin deklariere ich zwei Funktionszeiger, die letztendlich auf die beiden Push/Pop-Methoden im Hauptcode zeigen. In den Funktionszeiger-Deklarationen habe ich die Argumente weggelassen und das Programm kompiliert ok. Ist das richtig? Ich bin sicher, ich habe gelesen, dass die Argumente geliefert werden müssen. Ist das richtiges C99-Verhalten?Ist es richtig C99, dass Sie Argumente in Funktionszeigerdeklarationen in Strukturen nicht angeben müssen?

#include <stdio.h> 

#define INITIAL_STACK_SIZE 1000 

typedef struct stack 
{ 
    int index; 
    void *stack[INITIAL_STACK_SIZE]; 
    void* (*Pop)(); //<-- Is this correct? 
    void (*Push)(); //<-- Is this correct? 
} stack; 

stack CreateStack(void); 
void PushStack(stack*, void *); 
void *PopStack(stack*); 

stack CreateStack(void) 
{ 
    stack s = {0, '\0'}; 
    s.Pop = PopStack; 
    s.Push = PushStack; 
    return s; 
} 

void PushStack(stack *s, void *value) 
{ 
    if(s->index < INITIAL_STACK_SIZE) 
    { 
     s->stack[s->index++] = value; 
    } 
    else 
    { 
     fputs("ERROR: Stack Overflow!\n", stderr); 
    } 
} 

void *PopStack(stack *s) 
{ 
    if(s->index > 0) 
    { 
     return s->stack[--s->index]; 
    } 
    else 
    { 
     fputs("ERROR: Stack Empty!\n", stderr); 
     return NULL; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    stack s = CreateStack(); 

    s.Push(&s, "Hello"); 
    s.Push(&s, "World"); 

    printf("%s\n", (char*)s.Pop(&s)); 
    printf("%s\n", (char*)s.Pop(&s)); 

    return 0; 
} 

Ich habe versucht, die Argumente der Funktionszeiger hinzugefügt, aber ich habe einen Compiler-Fehler von Extraneous old-style parameter list. so richtig es ist vermute ich, würde aber eine andere Meinung lieben.

BEARBEITEN: Ich habe den oben genannten 'Extraneous Old-Style-Parameter-Liste' Fehler, weil ich den Typedef-Namen 'Stack' anstelle der Verwendung des Struct-Schlüsselwort mit 'Stack' zu definieren, es war die Struktur, die ich gerade definiere .

Ich verwende den Pelles C Compiler.

Antwort

2

Obwohl es auch unter GCC tut mit std=c99 -Wall -pedantic, ohne auch nur eine Warnung darüber, ich bin überrascht, dass es überhaupt kompiliert. Meiner Meinung nach ist das nicht schön cool.

Ich glaube, es ist eine viel bessere Idee folgend zu verwenden:

void* (*Pop)(struct stack*); 
void (*Push)(struct stack*, void*); 

Es ist zu kompilieren unter GCC 4.2 unter Verwendung der obigen Schalter.

Sonst könnte ich denken, Sie tun einen Fehler, indem Sie Push mit zwei Argumenten aufrufen. Das obige kompiliert und löscht diese Verwirrung.

+0

Ich habe tatsächlich einen Fehler in meinem Code gemacht.Ich habe den Typedef-Namen 'stack' verwendet, anstatt das Schlüsselwort struct mit 'stack' zu verwenden, um zu definieren, dass es die Struktur war, die ich gerade definiere. Danke. –

+0

Ja, ich habe den gleichen Fehler gemacht, als ich es das erste Mal versucht habe, also dachte ich, das könnte auch dein Problem gewesen sein. – zneak

+0

Nicht unhöflich sein, aber ich gab die gleiche Antwort zwei Minuten vor dem Zneak. – Trent

5

Das ist ein schlechter Stil (obwohl legal). Es wird funktionieren, aber es bedeutet, dass der Compiler Ihre Argumente nicht überprüfen kann. Also, wenn Sie aus Versehen Ihre Funktion wie folgt aufrufen:

s.Push(arg, &s); // oops, reverse the arguments 

der Compiler Sie nicht in der Lage sein zu sagen, der Ruf ist schlecht.

Vor der ANSI-Standardisierung hatte K & R C keine Prototypen; Es unterstützt nur Deklarationen, die den Rückgabetyp angegeben haben. Wenn Sie die Argumente weglassen, verwenden Sie diese archaische Funktion.

Auf gcc können Sie die Option -Wstrict-prototypes verwenden, um Warnungen zu aktivieren, wenn Sie sie verwenden.

+0

Und -Wissing-Prototypen auch verwenden. –

1

gcc (mit -pedantic -Wall -std=c99) hat kein Problem mit diesem Code:

typedef struct stack 
{ 
int index; 
void *stack[INITIAL_STACK_SIZE]; 
void* (*Pop)(struct stack *); 
void (*Push)(struct stack *, void *); 
} stack; 
+1

gcc benötigt die '-Wstrict-Prototypen', um Warnungen zu aktivieren, dass die Funktionsdeklaration kein Prototyp ist. –

+0

@R Samuel Klatchko, ich bin mir nicht sicher, was Sie meinen, ich zeige, dass der Code mit den richtigen Argumenten kompiliert mit gcc (obwohl er berichtet, dass es mit seinem scheitert) – Trent

+0

'-Wstrict-Prototypen' würde Instanzen von Nicht-Prototypen (dh die ursprüngliche schlechte Version 'void * (* Pop)()'. Ihr Code ist in Ordnung und hat dieses Problem nicht, aber die Verwendung von '-Wstrict-Prototypen' wird verhindern, dass das Problem wieder in den Code zurückgleitet. –

Verwandte Themen