C-Code gcc: Warum wird das nicht funktionieren

yxy

Lieutenant
Registriert
Juli 2014
Beiträge
570
Hallo,

Code:
int dummy();

const int dummy = 42;

Man könnte "oberflächlich" argumentieren: ich habe einmal dummy als eine Funktion und einmal als eine Variable deklariert. Das kann ja nicht funktionieren.

Ja, aber wenn wir die gcc-Kette "CPP, C Compiler, Assembler, Linker" anschauen,
wo genau wird der Fehler ausgegeben und warum?
 
Probier es aus? Ist das eine Hausaufgabe? Was wäre denn deine Vermutung?
 
  • Gefällt mir
Reaktionen: new Account()
Nein, das ist keine Hausaufgabe!!! Sondern ein Beispiel aus einer Internetquelle die sich mit Header befasst. Ziel ist es dabei möglichst Compile-Fehler zu erhalten und keine Luafzeitfehler. Dort steht aber nur dabei, dass es hier einen Compiler-Fehler geben wird, aber nicht warum.

Ich vermute, dass es etwas mit den Labels in Assembler zu tun haben könnte.
Denn wenn es 2 Labels mit dem Namen dummy gibt, weiß er ja nicht wo hin er springen soll.
 
ja probiers einfach aus - getrennt manuell bzw. wenn du es in der IDE kompilierst, steht eh dabei ob es ein Linker oder Compilerfehler ist.
 
Ok, es scheint der C-Compiler zu sein.
Die Frage die bleibt ist nun, warum?
 
  • Gefällt mir
Reaktionen: new Account()
Weil laut C Standard alle Identifier im gleichen Scope einen eindeutigen Namen haben müssen.

Shadowing ist aber erlaubt:
C:
void dummy() {
    int dummy = 7;
}

Das hat nichts mit Compiler/Linker/Assembler zu tun, das ist in der Sprache so definiert. Man könnte genauso seinen eigenen C Standard definieren, in dem Funktionen und Variablen den gleichen Namen haben dürfen.

Gruß
BlackMark
 
  • Gefällt mir
Reaktionen: BeBur und new Account()
Danke für deine Antwort.

Die Frage ist halt, warum es so definiert ist.
Ich könnte mir das anhand von Assembler so vorstellen:
Wenn ich 2 label mit dem gleichen Namen habe, weiß er ja nicht wohin er mit "jmp labelname" springen soll. Aber bin mir nicht sicher ob diese Überlegung passt.
 
Du kannst die Funktion dummy auch als Konstante nutzen. Dann weiß man nicht welche variable gemeint ist.

Soll jetzt der integer genommen werden oder die Funktion?
 
  • Gefällt mir
Reaktionen: abcddcba
Erklaerungen hast du ja schon bekommen.

Fuer die Zukunft, es gibt genug Moeglichkeiten um sich Ergebnisse vom Compiler anzusehen, selbst online gibt es fancy Tools: https://godbolt.org/
 
Du kannst die Funktion dummy auch als Konstante nutzen. Dann weiß man nicht welche variable gemeint ist.

Soll jetzt der integer genommen werden oder die Funktion?

So ganz kann ich dir leider nicht folgen. Eine Funktion in C ist doch keine Konstante, oder. In Assembler habe ich Label, da kann ein Label die Stelle einer Konstanten markieren, oder die Stelle an der eine Funktion beginnt.
 
Und das Label hat eine bestimmte Addresse (der Ort wo die Funktionsanweisungen stehen/ die Funktion beginnt). Diese entspricht der Konstante.

BlackMark schrieb:
Ich nehme an @new Account() meint Function Pointer, mit "Konstante".
Jein. Die Konstante ist in der Tat ein Function Pointer. Aber das erklärt ja die Kollision nicht.

BlackMark schrieb:
Wie schon gesagt, es wäre möglich (bis auf Function Pointer, da müsste man sich eine Regel festlegen) einen Compiler zu schreiben der gleiche Namen für Variablen und Funktionen zulässt, man hat sich in C aber dafür entschieden das nicht zu erlauben.
Vermutlich, weil die Sprache sonst unnötig komplex werden würde: Man müsste zwischen dem Übergeben von Variablen und Funktionspointern unterscheiden.
Und ganz wichtig: Es wäre ja eine Form von Typisierung, was er anscheinend ja garnicht mochte :D
 
Zuletzt bearbeitet:
yxy schrieb:
Wenn ich 2 label mit dem gleichen Namen habe, weiß er ja nicht wohin er mit "jmp labelname" springen soll. Aber bin mir nicht sicher ob diese Überlegung passt.
Nein. Diese Überlegung passt nicht. Das ist keine technische Limitierung. Zwischen C Code und Assembly stecken sehr viele Schritte die der Compiler macht, die Labels die am Ende raus kommen müssen überhaupt nichts mit dem ursprünglichen Code zu tun haben. Lokale Variablen auf dem Stack haben zum Beispiel überhaupt keine Labels im Assembly.

Wie schon gesagt, es wäre möglich (bis auf Function Pointer, da müsste man sich eine Regel festlegen) einen Compiler zu schreiben der gleiche Namen für Variablen und Funktionen zulässt, man hat sich in C aber dafür entschieden das nicht zu erlauben. Warum genau musst du wohl Dennis Ritchie fragen.

Ich nehme an @new Account() meint Function Pointer, mit "Konstante".

Edit:
@yxy Wenn deine Überlegung stimmen würde, wie erklärst du dir dann Overloading in C++?
C++:
#include <iostream>

void dummy(int a) {
    std::cout << a << std::endl;
}
void dummy(float a) {
    std::cout << a << std::endl;
}
void dummy(char a) {
    std::cout << a << std::endl;
}

int main() {
    dummy('7');
    dummy(7);
    dummy(7.0f);
    
    return 0;
}

Gruß
BlackMark
 
C++ ist eine andere Sprache. Daher erklärt das nichts. (ohne jetzt zu wissen wie es genau im Standard implementiert ist)
 
Natürlich ist C++ eine andere Sprache, gleich wie das fiktive C, in dem man Funktionen und Variablen mit dem gleichen Namen definieren darf.

Der TE glaubt aber, dass es einen technischen Grund gibt, wieso man das in C nicht machen darf. Das ist nicht der Fall. Um zu veranschaulichen wie falsch diese Annahme ist habe ich C++ Overloading hergenommen. Denn C++ wird, genauso wie C, am Ende zu Assembly runtergebrochen. Wenn Labelnamen ein Problem wären, dann wäre Overloading in C++ unmöglich. Es ist aber offensichtlich schon möglich, also muss die Annahme des TE falsch sein.

Gruß
BlackMark
 
  • Gefällt mir
Reaktionen: new Account()
Jo, es ist eben schlicht und einfach kein Feature der Programmiersprache C, dass Funktionen und Variablen den gleichen Namen haben können.
 
Hm? Das hat doch mit Typen überhaupt noch nichts zu tun. Es existiert ein Symbol, ein zweites Symbol mit demselben Namen wird definiert => Compiler Error.

C++ umgeht das durch Interface Mangling. Entsprechend ist es "bedingt" ein technisches Problem -- Spezifikation und Implementierung gehen Hand in Hand: C-als-Sprache sieht Symbole mit demselben Namen im selben Scope nicht vor, ergo ist es technisch nicht umgesetzt. Ich bin aber relativ sicher, daß man zu der Zeit, als C spezifiziert wurde, auf solche Feinheiten schlicht keinen Wert gelegt hat, Namen umdefinieren zu können im Sinne irgendeiner Polymorphie.

Warum auch? Wenn ich ein bool today definiere, dann hab ich vermutlich gemeint "heutiger Tag, ja/nein" und wenn ich dann komme mit datetime today, dann meine ich vermutlich was anderes und wenn mir die Sprache (egal welche!) das verbietet, dann kommt mir das zugute und schränkt mich eben NICHT (unnütz) ein.


Exakt diese Deklaration ist, aus Sicht des Programmierers, exakt der Grund, warum man das macht. C verlangt es vom Programmierer, aber wenn man jetzt VB hernimmt (oder VBS) oder PowerShell, da macht es einen gravierenden Unterschied, ob ich mir meine Variable deklariere, sie einfach so verwende und/oder typisiere: im ersteren Fall weiß der Compiler, was es sein soll und kann entsprechend Platz reservieren; im zweiteren muß er vom worst case ausgehen, hat keine Angaben über das "was" und wird entsprechend meinen bool von oben aus dem Beispiel mit einem datetime oder einem unsigned long oder sonstwomit überschreiben, ohne daß ich das merke, oder wird wie bei VB(s) oder PS einfach eine neue Variable anlegen, wenn ich mich verschrieben hab.

MIT Option Explicit bzw. Typdeklaration in VB(s) und PS krieg ich dann den erwünschten Compilerfehler(VB) bzw Laufzeitfehler (PS läuft in einer VM, streng genommen ist es also auch ein Compilerfehler, aber man kompiliert ja nicht selber und merkt es daher erst zur Laufzeit, daß da was nicht paßt).
 
Zurück
Oben