sizeof style: sizeof (Typ) oder sizeof variable?

22

Ich habe zwei Arten der Verwendung sizeoffür speicherbezogene Vorgänge gesehen (z. B. in memsetoder malloc):

  • sizeof(type), und
  • sizeof variable oder sizeof(variable)

Welchen würden Sie bevorzugen, oder würden Sie eine Mischung der beiden Stile verwenden, und wann würden Sie jeden Stil verwenden? Was sind die Vor- und Nachteile eines jeden Stils und wann benutzt du sie?

Als Beispiel kann ich die folgenden Situationen sehen, in denen ein Stil hilft und der andere nicht:

Wenn Sie die falsche Zeiger-Indirektion erhalten:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

Wenn sich der Typ ändert:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */
congusbongus
quelle

Antworten:

30

Ich ziehe sizeof(variable)vorbei sizeof(type). Erwägen:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

gegen

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

Im ersten Fall ist es einfach zu überprüfen, ob die richtigen Größen übergeben werden memset. Im zweiten Fall müssen Sie die oberen und unteren Abschnitte ständig überprüfen, um sicherzustellen, dass Sie konsistent sind.

vy32
quelle
4
Wenn Sie den Typ der Variablen ändern, muss sich auch der Code ändern, der davon ausgeht, dass der Typ geändert wird. Ich denke, es ist vorzuziehen, Code mit so wenig Abhängigkeit vom Typ wie möglich zu korrigieren. (Ich bin damals von einem großen 16-Bit-zu-32-Bit-Konvertierungsprojekt beeinflusst.)
Gort the Robot,
Dies ist vorzuziehen, wenn Sie mit C-Arrays arbeiten, bei denen es nicht üblich ist, ein typedef zu erstellen, sondern Dinge wie char array [MAX_SIZE] verwenden.
Mattnz
@ vy32: Wrong 1: "sizeof (array) gibt NICHT die Größe des Arrays zurück ... Größe des Zeigers auf das Array" - Wenn arrayes sich in der Tat um ein C-Array handelt, wird sizeof(array)die Anzahl der zum Speichern der Array-Elemente erforderlichen Bytes zurückgegeben . Wenn arrayes sich um einen Zeiger auf das erste Element eines zerfallenen C-Arrays handelt, gilt Ihre Anweisung. Wenn Sie ein C-Array als Funktionsargument übergeben, sieht es wie ein Zeiger in der Funktion aus. Alle Informationen, die beweisen, dass es sich um ein Array handelt, gehen ebenso wie die Größe verloren. Deshalb ist es verfallen . Falsch 2: "Arrays existieren in C eigentlich nicht; ... einfach syntaktischer Zucker für Zeiger."
Johann Gerell
9

Es ist (wie immer) vorzuziehen, Ihre Absicht so direkt wie möglich wiederzugeben.

Ist die Absicht, gegen den Speicher einer vorhandenen Variablen zu arbeiten? Wenn ja, verwenden Sie sizeof(variable), da dies so genau wie möglich zeigt, dass Sie sich um den Speicher der Variablen selbst kümmern.

Soll der Typ berechnet werden, um beispielsweise zu bestimmen, wie viel Speicher für eine neue Instanz reserviert werden soll? Wenn ja, dann benutze sizeof(type).

Das heißt, ich bevorzuge

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

Über

bar = (struct foo *) malloc(sizeof(*bar));

wie die letzteren Fall aussieht wie Sie versuchen , eine Variable zuzugreifen, die noch nicht existiert.

Andererseits bevorzuge ich

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

Über

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

da die Absicht eindeutig darin besteht, den Inhalt der Variablen auf Null zu setzen, ist dies die Variable, gegen die wir vorgehen sollten. Der Versuch, die Typ-Metadaten zu verwenden, verwirrt hier nur die Dinge.

Aidan Cully
quelle
Das tue ich immer, aber das ist eine Frage des persönlichen Geschmacks. Ich halte das void *automatische Casting auf andere Zeigertypen für eine Fehlfunktion.
Aidan Cully
3

Ich würde es vorziehen , in beträchtlichem Ausmaß sizeof(type)über sizeof variable. Auch wenn Sie sich mehr Gedanken über den Typ machen und weitere Änderungen vornehmen müssen, können Sie Zeiger-Indirektionsfehler vermeiden, die zu den häufigsten Fehlerursachen in C gehören .

Ich würde mich nicht so sehr um Bugs kümmern, bei denen der Typ sizeof(type)geändert wird. Wenn Sie den Typ einer Variablen ändern, sollten Sie einen schnellen Scan durchführen, um festzustellen, wo diese Variable verwendet wird und ob Sie sizeof(type)Anweisungen ändern müssen . Obwohl es immer die Möglichkeit gibt, dies falsch zu verstehen, besteht ein viel geringeres Risiko als bei Zeiger-Indirektionsfehlern.

Ein Vorteil von sizeof variableist für Arrays, aber in der Praxis habe ich festgestellt, dass das Übergeben von Arrays als Paare von first / len viel häufiger vorkommt (in diesem Fall wird nur die Länge verwendet) Array / Pointer-Zerfall, wie in diesem Beispiel:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}
congusbongus
quelle
2
"Schneller Scan, um zu sehen, wo diese Variable verwendet wird ... es besteht immer die Möglichkeit, dass dies falsch ist" - für mich ist dies die größte Gefahr, sizeof (Typ) zu machen, weshalb ich sizeof (Variable) immer mache. Das Endergebnis dieser Gefahr ist, dass möglicherweise noch alles kompiliert wird, und selbst wenn Sie einen Fehler machen, dauert es möglicherweise mehr als ein Jahr oder es kommt zu zufälligen Abstürzen und Pufferverfälschungen, bevor Sie es abfangen. Und ich konnte die Verbindung zwischen dieser Frage und "Zeiger-Indirektionsfehlern" nicht herstellen (offensichtlich beträgt mein Zeitfenster pro Frage etwa 30 Sekunden).
DXM
@DXM Mit der Größe des Operanden, wenn es ein Wert ist, dann ist es sizeof var; Wenn es ein Zeiger ist, ist es sizeof *var. Dies ist auch etwas, was die Leute falsch machen können, und der Compiler wird es gerne ohne Beschwerde annehmen. Ich behaupte, dass diese Fehler viel schwerer zu erkennen und häufiger sind als Fehler mit der sizeof(type)Form.
Congusbongus
1
Ihre beiden richtigen C-Typen und die Größe des Operators sind grundlegend fehlerhaft und werden niemals zuverlässig sein, nichts, was Sie als Programmierer tun können, um das Problem zu beheben.
Mattnz
Wenn der Beitrag mit Tags versehen ist C, ist das Posten von C-Code informativer als C ++ - Code mat3_t::mat3_t(...).
chux
0

Ziel ist es, Redundanz zu beseitigen. Wenn Sie sizeof für eine Operation verwenden, die sich auf eine Variable bezieht, müssen Sie dies natürlich in sizeof widerspiegeln. Ja, Sie können es wie im ersten Beispiel vermasseln, aber die Heilung ist nicht vom Typ, sondern vom Typ * var, der korrekt zum Ziel passt.

Um solche Probleme abzumildern, ist es üblich, Makros, Vorlagen und ähnliche Tools zu verwenden, die für den Anwendungsfall geschult sind, und nicht nackte Größe.

Siehe mein CLEAR-Makro , das ausschließlich anstelle des nackten Memset verwendet wird. Ich habe meinen Arsch mehrmals gerettet, wenn ein Tippfehler aufgetreten ist oder wenn ein Strukturinhalt einen Vektor oder eine Zeichenfolge gefunden hat ...

Balog Pal
quelle
Makros wie diese gaben
Cs Makroprogrammierung
@mattnz: bitte zeige die bessere Alternative. Es ist viel einfacher, abstrakte Dinge zu besprechen, als tatsächlich funktionierende Programme zu erstellen
Balog Pal,
1
Das verknüpfte Makro ist C ++ und dieser Beitrag ist mit "C" (sie sind verschiedene Sprachen) gekennzeichnet. Ada wäre mein Vorschlag.
Mattnz
@mattnz: und dasselbe Thema zeigt, wie man C auf ähnliche Weise durchsetzt. Sie scheinen den Punkt, der nicht die eigentliche Inhaltsimplementierung, sondern die sicherere Verwendung im Vergleich zu Rohmaterial darstellt, völlig zu übersehen. Übrigens auch lesbar.
Balog Pal
0

Geschäftslogik definiert Ihre Wahl.

  1. Wenn sich Ihr Code auf eine bestimmte Variable bezieht und diese Variable fehlt, ist Ihr Code nicht sinnvoll - wählen Sie sizeof(var)

  2. Wenn Sie Code für eine Reihe von Variablen mit einem bestimmten Typ verwenden, wählen Sie sizeof(type). Normalerweise benötigen Sie dies, wenn Sie eine haben, typedefdie viele Variablen definiert, die Sie je nach Typ unterschiedlich verarbeiten (z. B. Serialisierung). Möglicherweise wissen Sie nicht, welche dieser Variablen in zukünftigen Codeversionen verbleibt. Daher ist es logisch richtig, Typ als Argument auszuwählen. Sogar das Ändern von solchem typedefwird Ihre Größe der Linie nicht beeinflussen.

Riga
quelle
-1

Je nach Verwendungszweck könnte sizeof (variabel) die beste Lösung sein. Auf diese Weise können Sie Ihren Variablentyp bei Bedarf ändern, ohne alle Einträge für den Typ zu korrigieren. Aber auch hier kommt es auf Ihr Ziel an.

Pedro Perez
quelle