Behandelt C sizeof(…) und sizeof … in diesem Fall richtig?

Lesezeit: 6 Minuten

Benutzeravatar von ccoder987
coder987

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:

  1. Tut rofl in sizeof(rofl) richtig auswählen rofl Typ Wegen der Klammern?
  2. 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.

  • 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

Benutzeravatar von MM
MM

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
}

  • Es gibt drei spezielle Kontexte für Bezeichner: Bezeichnungsnamen, Strukturtags und Strukturmitglieder. Aber in allen anderen Kontexten teilen sich alle Bezeichner einen gemeinsamen Namensraum: Es gibt keine eindeutigen Namensräume für Bezeichner für Typnamen gegenüber Variablennamen gegenüber Funktionsnamen usw. rolf Hier ist ein erfundenes Beispiel: rolf Das solltest du explizit erklären

    als Bezeichner (Name) für ein Objekt verbirgt

    als Bezeichner für einen Typedef-Namen. Dies ist nicht klar, da C mehrere Namensräume hat. Seine Verwendung als Etikett beispielsweise würde die Verwendung für ein Objekt nicht verbergen. Eine Person könnte denken, dass „sizeof(rofl)“ als die Größe des Typedef-Namens oder die Größe des Objekts analysiert werden könnte; Sie könnten beide sichtbar sein, wenn sie sich in separaten Namensräumen befinden. Wie wählt der Compiler aus? Aber wenn wir erklären, dass der typedef-Name wegen des Versteckens im selben Namensraum nicht sichtbar ist, dann ist klar, wie er analysiert wird.


  • – Eric Postpischil

    15. November 2017 um 1:39 Uhr

    Übrigens verwendet der C-Standard „hide“ statt „shadow“.


  • – Eric Postpischil

    15. November 2017 um 1:41 Uhr

    @EricPostpischil Re. Ihr erster Kommentar, mein Text “für den Rest des aktuellen Geltungsbereichs bedeutet dieser Bezeichner immer den Variablennamen”, vermittelt das bereits? Ich habe sogar versucht, dies im zweiten Absatz zu bekräftigen, indem ich sagte, dass die verborgene Bedeutung niemals verwendet wird.


  • – MM sizeof 15. November 2017 um 1:45 Uhr

    Nun, die Aussage „dieser Bezeichner meint immer den Variablennamen“ ist eigentlich nicht wahr. Ein Bezeichner kann gleichzeitig der Name eines Objekts, der Name eines Labels, der Name mehrerer Struct- oder Union-Mitglieder und ein Tag einer Struktur, Union oder Enumeration sein. Diese Möglichkeiten werden durch den syntaktischen Kontext unterschieden. Diese Antwort erklärt also nicht wirklich, wie C-Namensräume im Kontext der Frage funktionieren – die Frage des OP fragt im Wesentlichen, ob die beiden syntaktischen Formen von

    Typnamen von Objektnamen unterscheiden…

  • – Eric Postpischil

    15. November 2017 um 1:53 Uhr

    … Daher denke ich, dass es hilfreich sein könnte, klarzustellen, dass, obwohl C mehrere Namensräume für Bezeichner hat, Typedef-Namen und Objektnamen einen Namensraum teilen (zusammen mit Funktionsnamen), sodass einer den anderen ausblenden kann, im Gegensatz zu Labels.


– Eric Postpischil
15. November 2017 um 1:54 Uhr

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 roflder 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 intdie 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 sizeofoder

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 roflZum 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));
}

. roflIn 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

1392520cookie-checkBehandelt C sizeof(…) und sizeof … in diesem Fall richtig?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy