web-dev-qa-db-fra.com

sizeof style: sizeof (type) ou sizeof variable?

J'ai vu deux styles d'utilisation de sizeof pour des opérations liées à la mémoire (comme dans memset ou malloc):

  • sizeof(type), et
  • sizeof variable Ou sizeof(variable)

Lequel préféreriez-vous, ou utiliseriez-vous un mélange des deux styles, et quand utiliseriez-vous chaque style? Quels sont les avantages et les inconvénients de chaque style et quand les utilisez-vous?

À titre d'exemple, je peux voir la paire de situations suivante où un style aide et l'autre non:

Lorsque vous obtenez l'indirection du pointeur incorrecte:

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

Lorsque le type change:

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

Je préfère sizeof(variable) sur sizeof(type). Considérer:

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

vs.

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

Dans le premier cas, il est facile de vérifier que les bonnes tailles sont transmises à memset. Dans le deuxième cas, vous devez constamment revoir les sections supérieure et inférieure pour vous assurer que vous êtes cohérent.

30
vy32

La préférence (comme toujours) est de refléter votre intention aussi directement que possible.

L'intention est-elle d'opérer contre la mémoire d'une variable existante? Si c'est le cas, utilisez sizeof(variable), car cela montre aussi fidèlement que possible que c'est la mémoire de la variable elle-même qui vous tient à cœur.

L'intention est-elle d'effectuer un calcul sur le type, par exemple pour déterminer la quantité de mémoire à allouer pour une nouvelle instance? Si c'est le cas, utilisez sizeof(type).

Autrement dit, je préfère

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

plus de

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

comme dans ce dernier cas ressemble comme si vous essayez d'accéder à une variable qui n'existe pas encore.

Par contre, je préfère

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

plus de

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

comme l'intention est clairement de remplir à zéro le contenu de la variable, c'est donc la variable contre laquelle nous devons opérer. Essayer d'utiliser le type de métadonnées confond simplement les choses, ici.

9
Aidan Cully

Je préférerais largement sizeof(type) à sizeof variable. Même si cela vous oblige à vous soucier davantage du type et à apporter plus de modifications, il vous aide à éviter les erreurs d'indirection de pointeur, qui se classent parmi les causes les plus courantes de bogues en C .

Je ne m'inquiéterais pas tellement des bugs où le type dans sizeof(type) est changé; chaque fois que vous modifiez le type d'une variable, vous devez effectuer un balayage rapide pour voir où cette variable est utilisée et si vous devez modifier des instructions sizeof(type). Même s'il y a toujours une chance de se tromper, cela présente un risque beaucoup plus faible que les erreurs d'indirection de pointeur.

Un avantage de sizeof variable Est pour les tableaux, mais dans la pratique, j'ai trouvé que le passage de tableaux sous forme de paires de premier/len est beaucoup plus courant (auquel cas il suffit d'utiliser la longueur), en plus il est également très facile à obtenir la mauvaise taille en raison de la décomposition du tableau/pointeur, comme dans cet exemple:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}
3
congusbongus

L'objectif est de supprimer la redondance. Si vous utilisez sizeof pour une opération liée à une variable, vous devez évidemment le refléter dans sizeof. Oui, vous pouvez gâcher comme dans le premier exemple, mais le remède n'est pas d'utiliser le type, mais * var, correspondant correctement au but.

Pour atténuer ces problèmes, il est habituel d'utiliser des macros, des modèles et des outils similaires formés pour le cas d'utilisation plutôt que sizeof nu.

Voir mon macro CLEAR qui est utilisé exclusivement à la place du memset nu. J'ai sauvé mon cul plusieurs fois en cas de faute de frappe dans l'indirection ou lorsqu'un contenu de structure récupérait un vecteur ou une chaîne ...

0
Balog Pal

La logique métier définit votre choix.

  1. Si votre code fait référence à une variable particulière et sans cette variable, votre code n'a aucun sens - choisissez sizeof(var)

  2. Si votre code traite d'un ensemble de variables de type particulier - choisissez sizeof(type). Habituellement, vous en avez besoin si vous avez un typedef qui définit de nombreuses variables que vous traitez différemment en fonction de leur type (par exemple la sérialisation). Vous ne savez peut-être pas laquelle de ces variables restera dans les futures versions de code, donc choisir le type comme argument est logiquement correct. Même le changement d'un tel typedef n'affectera pas la taille de votre ligne.

0
Riga