Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 560
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von starcow »

Schönen Nachmittag liebe zfx Gemeinde :-)

Ich kann mir nicht helfen, doch würde ich euch gerne aktuell an einer kleinen Verwirrung meinerseits teilhaben lassen. (:

Wieso benötigt der Compiler (gcc, als auch clang) bei Pointer auf struct manchmal eine forward declaration - und manchmal nicht?

Zwei Beispiele:
Gegeben sei eine Funktion mit entsprechendem Prototyp (der ja typischerweise später dann im .h file schlummert):

Folgendes lässt sich ohne Warnung compilieren (abgesehen von [-Wunused-parameter]).

Code: Alles auswählen

struct s * func(struct s *);
struct s * func(struct s * p){ return (struct s *)0; }

Dies jedoch nicht!

Code: Alles auswählen

void func(struct s *);
void func(struct s * p){ return; }

Code: Alles auswählen

foo.c:2:18: warning: declaration of 'struct s' will not be visible outside of this function [-Wvisibility]
void func(struct s *);
                 ^
foo.c:3:18: warning: declaration of 'struct s' will not be visible outside of this function [-Wvisibility]
void func(struct s * p){ return; }
                 ^
foo.c:3:6: error: conflicting types for 'func'
void func(struct s * p){ return; }
     ^
foo.c:2:6: note: previous declaration is here
void func(struct s *);
     ^
2 warnings and 1 error generated.
Bei letzterem ist eine forward declaration notwendig:

Code: Alles auswählen

struct s;
void func(struct s *);
void func(struct s * p){ return; }
Natürlich mach ich gerne eine forward declaration. Nur frag ich mich, wieso es nicht mehr funktioniert, wenn der Rückgabetyp der Funktion nicht vom entsprechenden (struct pointer) Typ ist.
Zuletzt geändert von starcow am 25.04.2024, 22:02, insgesamt 1-mal geändert.
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Hannes
Beiträge: 43
Registriert: 11.06.2008, 06:04

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von Hannes »

Hallo starcow,

ich hab mal das Beispiel in einen Online-Kompiler geschmissen, bekomme aber keine Fehlermeldung.
Daher kann ich deine Fehlermeldung nicht reproduzieren.

https://godbolt.org/z/dTon1ez47

Liebe Grüße

Hannes
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von Krishty »

Die konkrete Frage kann ich dir nicht beantworten, aber ich befürchte, dass du nicht ganz verstanden hast, dass die Forward Declaration hier nicht optional ist. (Wir sprechen von C statt C++, oder?)

Wenn deine Funktion einen Zeiger auf s erhalten soll, musst du struct s * in die Parameterliste schreiben, korrekt.

Wenn der Typ struct s noch nie vorher deklariert wurde, bewirkt struct s eine Deklaration lokal in der Parameterliste. Und zwar nur für diese Funktion.

Wenn du das zwei Mal hintereinander machst, deklarierst du zwei unterschiedliche struct s die zwar gleich heißen, aber unterschiedliche Typen sind.

void func(struct s *); // ersten Typ struct s deklariert
void func(struct s * p){ return; } // zweiten, UNTERSCHIEDLICHEN Typ struct s deklariert


Darum auch der Fehler mit dem uneindeutigen Funktionstyp.

Was du „Forward Declaration“ nennst ist tatsächlich die Deklaration eines struct s, so dass sich beide struct s der Parameterlisten auf das selbe, zuvor deklarierte struct s beziehen anstatt jeweils ein neues zu deklarieren.

Meine Annahme ist, dass struct s im Rückgabewert für das globale Scope gilt statt für Function Scope. Bin aber nicht sicher.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von Krishty »

Hannes hat geschrieben: 25.04.2024, 20:12ich hab mal das Beispiel in einen Online-Kompiler geschmissen, bekomme aber keine Fehlermeldung.
Du musst -x c übergeben, damit der Code als C statt als C++ kompiliert. Und beide Beispiele separat kompilieren. https://godbolt.org/z/ed3j99W3z
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
gombolo
Establishment
Beiträge: 161
Registriert: 26.01.2011, 20:33

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von gombolo »

Bin auch maximal verwirrt, aber kann es an dem Rückgabewert void* liegen. Woher soll der Compiler wissen was da zurückgegeben wird...würde ich mal vermuten.

EDIT: mit Krishty zeitgelich gepostet, aber die Begründung von Krishty hörst sich plausibler an :)
Benutzeravatar
starcow
Establishment
Beiträge: 560
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von starcow »

Danke euch für die Anteilnahme! :-)
Es ist tatsächlich C-Code und nicht C++, wie Krishty richtig antizipiert hatte (war mir nicht bewusst, dass das hier ein Unterschied macht).

@gombolo
Danke für den Hinweis. Tatsächlich sollte auch im letzten Beispiel der Rückgabetyp natürlich void sein - und nicht void * (habe es jetzt angepasst).

@Krishty
Mit deiner Erklärung macht das jetzt alles Sinn! *Top*!
Das erklärt auch schlüssig, wieso der Compiler zwei verschiedene Typen "moniert", obwohl ja zweimal das selbe dasteht (lehrreich!).
Folglich hätte ich jetzt auch vermutet, dass wenn das struct im Rückgabetyp enthalten ist, es dadurch für den globalen Scope deklariert wurde.

Code: Alles auswählen

struct s;
Also Ist das tatsächlich gar keine forward declaration (wie du ja sagst). Wie wird das richtigerweise genannt - einfach "declaration"?
Denn Folgendes ist ja möglich:

Code: Alles auswählen

struct s; // declaration?

struct s // Keine redefinition - weil bis hier hin blos deklariert (und nicht definiert)?
{
    int x;
};
Folgendes aber NICHT:

Code: Alles auswählen

struct s
{
    int x;
};

struct s  // error: redefinition of 'struct s'
{
    int x;
};
Zuletzt geändert von starcow am 26.04.2024, 00:12, insgesamt 1-mal geändert.
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Pointer auf struct - ohne forward declaration (wieso gehts manchmal?)

Beitrag von Schrompf »

Wow, hier lernt man noch was.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten