In C gibt es zwei verschiedene Namespaces von Typen: einen Namespace von struct/union/enum-Tag-Namen und einen Namespace von typedef-Namen.
name.c
$ cat name.c
#include<stdio.h>
typedef long long long2;
int long2 () {
return 4;
}
int main() {
printf("hello, world!");
return 0;
}
$ gcc name.c -o name
name.c:4: error: 'long2' redeclared as different kind of symbol
name.c:3: error: previous declaration of 'long2' was here
$
name2.c
$ cat name2.c
#include<stdio.h>
int four() {
return 4;
}
struct dummy {
int member;
};
int main() {
struct dummy four;
}
$ gcc name2.c -o name2
$
Ich versuche, C-Namespace-Konflikte zu verstehen.
Warum gibt es im ersten Fall einen Konflikt? Gehören auch Funktionen zum Typedef-Namensraum?
Warum gibt es im zweiten Fall überhaupt keinen Konflikt? Die Funktion und die Variable heißen beide vier. Warum lässt der Compiler das zu? Wie ist &four soll gelöst werden?
schott
C hat vier verschiedene Namensräume für Bezeichner:
Markennamen (die goto Typ).
Tags (Namen von Strukturen, Vereinigungen und Aufzählungen).
Mitglieder von Strukturen und Unions (diese haben einen eigenen Namensraum pro Struktur/Union).
Alle anderen Bezeichner (Funktionsnamen, Objektnamen, Typ(def)-Namen, Aufzählungskonstanten usw.).
Siehe auch C99 6.2.3.
Ihre beiden Fragen können also wie folgt beantwortet werden:
Ja, Funktionsnamen und Typedef-Namen teilen sich denselben Namensraum.
Kein Konflikt, da der Compiler Bereichsregeln (für Funktions- oder Objektnamen) verwendet. Der Bezeichner in der Hauptsache wird gesagt Schatten den globalen Funktionsnamen, wovor Ihr Compiler Sie warnen wird, wenn Sie die Warnstufen hoch genug setzen.
Teilen sich Structs/Unions/Enums einen Namensraum? dh kann struct T und union T passen gut zusammen?
– iBug
17. November 2017 um 10:00 Uhr
iBug, nein, das können sie nicht, da struct, unions und enumerations den gleichen Namensraum (Tags-Namensraum) teilen.
– dandev486
18. August um 11:39 Uhr
kennytm
Aber der entscheidende Punkt in Ihren Beispielen ist nicht der Namensraum, sondern der Umfang der Namen.
Im name.cbeide long2 sind “normale Bezeichner” (haben denselben Namensraum), und beide sind im selben Bereich definiert, sodass ein Konflikt besteht. (C99 §6.7/3)
Wenn name2.cdie lokale Variable four ist in einem Bereich, der tiefer ist als die Funktion fouralso die Variable verbirgt sich die Funktion four (C99 §6.2.1/4).
pmg
Ihr 2. Beispiel zeigt nicht “kein Konflikt”. Es gibt einen Konflikt! Versuche dies:
#include <stdio.h>
int four(void) { return 4; }
struct dummy { int member; };
int main(void) {
struct dummy four;
four.member = four();
}
Und jetzt das
#include <stdio.h>
int four(void) { return 4; }
struct dummy { int member; };
int main(void) {
int (*fx)(void) = four; /* "save" function */
struct dummy four; /* hide it */
four.member = fx(); /* use "hidden" fx */
}
In Ihrem 2. Beispiel die Variable fourverbirgt sich die Funktion four().
Um deine zwei Fragen schnell zu beantworten.
Q1. Warum gibt es im ersten Fall einen Konflikt? Gehören auch Funktionen zum Typedef-Namensraum?
A1. Ja, Kennungen für Funktionen und typdefinierte Typen denselben Namensraum teilen. Es gibt also einen Konflikt.
Q2. Warum gibt es im zweiten Fall überhaupt keinen Konflikt? Die Funktion und die Variable heißen beide vier. Warum lässt der Compiler das zu? Wie soll &four aufgelöst werden?
A2. In Ihrem zweiten Beispiel gibt es keinen Konflikt, obwohl die beiden genannten Bezeichner vier gehören zum selben Bezeichner-Namespace, der ist Ordinary namespace. Denn der Variablenbezeichner vier in der Hauptsache ist in a Funktionsumfangwährend die Funktionskennung vier in einem Dateibereich. Letzteres wird also von ersterem als grundlegende Geltungsbereichsregel verdeckt. Wenn Sie die Variable verschieben vier zum Dateibereich (global) wie unten, sehen Sie einen Fehler.
...
struct dummy four; // Error! there's a previous definition
// in this file scope(global).
int main() {
// struct dummy four; // Commented out.
}