Im folgenden Code sind die Funktionen test
und test2
gleichwertig?
typedef int rofl;
void test(void) {
rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?
}
void test2(void) {
rofl * rofl = malloc(sizeof *rofl); // Is the final rofl here the VARIABLE?
}
Mit anderen Worten:
- Tut
rofl
in sizeof(rofl)
richtig auswählen rofl
Typ Wegen der Klammern?
- Tut
rofl
in sizeof *rofl
richtig auswählen rofl
Variable aufgrund eines Mangel von Klammern?
Notiz: Dies ist ein albern aussehendes Beispiel, aber in der Praxis kann es vorkommen, dass Sie einen Typnamen haben, der mit einem Variablennamen identisch ist. Daher die Frage.
In beiden Fällen das letzte rofl
ist der Variablenname. Ein Variablenname ist im Geltungsbereich, sobald er erscheint; und für den Rest des aktuellen Geltungsbereichs diese Kennung in einem gewöhnlichen Kontext
bedeutet immer den Variablennamen. sizeof
Das
-Operator führt keine Sonderfälle für die Namenssuche ein. Tatsächlich gibt es keine Sprachkonstrukte, die die verborgene Bedeutung eines Bezeichners verwenden.
In der Praxis ist es eine gute Idee, nicht denselben Bezeichner für einen Typ und einen Variablennamen zu verwenden.
typedef int A; // "A" declared as ordinary identifier, meaning a type name
struct A { A A; }; // "A" declared as struct tag and member name -- OK as these are three different name spaces. Member type is "int"
A main() // int main() - ordinary context
{
struct A A(); // "A" declared as ordinary identifier, meaning a function name; hides line 1's A
// A C; // Would be error: ordinary A is a function now, not a typedef for int
struct A B; // OK, struct tags have separate name space
A:+A().A; // OK, labels and struct members have separate name space, calls function
goto A; // OK, label name space
}
Vlad aus Moskaus Benutzer-Avatar
rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?
Vlad aus Moskau rofl
In dieser Erklärung rofl
der Name der Variablen rofl
verbirgt den Typedef-Namen int *
. Daher wird im sizeof-Operator der Zeiger verwendet
das heißt, der Ausdruck hat den Typ
rofl * rofl = malloc(sizeof *rofl);
. rofl
Gleiches gilt für diese Erklärung rofl
außer dass ein Ausdruck mit dem dereferenzierten Zeiger verwendet wird int
die den Typ des Typedef-Namens hat
das ist der typ
sizeof unary-expression
sizeof ( type-name )
. unary-expression
Es scheint, dass die Verwirrung aufgrund dieser C-Grammatikdefinition entsteht
Jedoch
primary-expression:
( expression )
//...
kann ein primärer Ausdruck sein, der ein in Klammern eingeschlossener Ausdruck ist. x
Aus dem C-Standard (6.5.1 Primäre Ausdrücke)
sizeof x
Also zum Beispiel wenn
sizeof( x )
ein Name einer Variablen ist, dann können Sie beides schreiben
sizeof ( x )
operator primary expression
oder
+ x
Zur Verdeutlichung könnten Sie Leerzeichen zwischen dem sizeof-Operator und dem primären Ausdruck einfügen
+ ( x )
Betrachten Sie zum Vergleich einen anderen unären Operator: das unäre Plus. Du kannst zum Beispiel schreiben sizeof
oder
Ersetzen Sie jetzt einfach das unäre Plus durch einen anderen unären Operator
.
typedef struct rofl { int x; } rofl;
void test(void) {
rofl * rofl = malloc(sizeof( struct rofl));
}
Was das Verbergen von Namen betrifft, ist das Problem für Strukturen, Vereinigungen und Aufzählungen lösbar, da ihre Namen Schlüsselwörter für Tags enthalten. struct rofl
Zum Beispiel
In dieser Funktion mit dem Operator sizeof wird type-name verwendet
typedef struct rofl { int x; } rofl;
void test(void) {
rofl * rofl = malloc(sizeof( rofl));
}
. rofl
In dieser Funktion struct rofl *
Beim sizeof-Operator wird ein primärer Ausdruck mit der Variablen verwendet
das hat den Typ rofl
. sizeof
Es gibt kein „Aussuchen“ oder „Auswählen“. In beiden Fällen die sizeof
jeweils bezeichnet
Der Aufruf ist aufgrund von Bereichsregeln die Variable, nicht der Typ. Die Variable wird im inneren Geltungsbereich deklariert und überschreibt somit den Typnamen. Die Klammerung des Arguments an die
Warum haben die Leute das abgelehnt? Es ist eine vollkommen vernünftige Frage, und die Antwort ist nicht klar, da C mehrere Namensräume hat, sodass einige Namen mehrere sichtbare Bedeutungen haben können, sodass Sie diese Frage nicht endgültig beantworten können, es sei denn, Sie wissen ausdrücklich, dass Typedef-Namen und Objektnamen dies gemeinsam haben gleichen Namensraum und können sich gegenseitig verstecken.
– Eric Postpischil
15. November 2017 um 1:43 Uhr
Die kurze Antwort ist nein, die Klammern machen keinen Unterschied.
sizeof
ist ein Operator, keine Funktion, daher sind die Klammern lediglich überflüssig.– Benutzer207421
15. November 2017 um 1:47 Uhr
Übrigens, um Ihre Frage 2 explizit zu beantworten, ja, das Fehlen von Klammern erzwingt das
sizeof
operand nur eine Option haben: Es muss eine Art „unärer Ausdruck“ sein, also kann es kein Typedef-Name sein. Bei Frage 1 sind die Klammern nicht vorhanden weil der Compiler einen Typedef-Namen verlangt. Das Ding in Klammern, wenn es nur ein Bezeichner ist, kann an diesem Punkt nur gültig der Name einer Typdefinition, Funktion oder eines Objekts sein, sodass der Compiler nur eine Auflösung findet; es muss nicht gewählt werden.– Eric Postpischil
15. November 2017 um 1:48 Uhr
@EricPostpischil Du hast dir selbst widersprochen. Entweder machen die Klammern einen Unterschied oder nicht. unärer Ausdruck kann ein sein Kennung.
– Benutzer207421
15. November 2017 um 1:55 Uhr
@EJP: Es gibt keinen Widerspruch. Wenn Klammern vorhanden sind, sind zwei syntaktische Optionen möglich. Wenn Klammern fehlen, gibt es nur eine syntaktische Option. Mit einer Kennung in Klammern,
sizeof (foo)
kann entweder mit dem „sizeof
unärer Ausdruck“ gemäß Abschnitt 6.5.3 der C-Norm oder dem „sizeof (
Modellname)
“ in der gleichen Klausel. Die Übereinstimmung wird dann durch die Bedeutung des Bezeichners bestimmt, nicht durch die lokale Syntax. Ohne Klammern ist nur die erste möglich.– Eric Postpischil
15. November 2017 um 1:59 Uhr