“C” sizeof avec un type ou une variable

cemment, quelqu’un a recommandé à un autre utilisateur d’utiliser sizeof var au lieu de sizeof (type). J’ai toujours pensé que c’était juste un choix de style. Y a-t-il une différence significative? Par exemple, les lignes avec f et ff ont été considérées meilleures que les lignes avec g et gg:

typedef struct _foo {} foo; foo *f = malloc(count * sizeof f); foo *g = malloc(sizeof(foo) * count); foo **ff = malloc(count * sizeof *ff); foo **gg = malloc(sizeof(foo*) * count); 

A mon avis, le premier set est juste une question de style. Mais dans la deuxième paire de lignes, la seconde supplémentaire * peut facilement être confondue pour une multiplication.

Si le type de la variable est modifié, le sizeof ne sera pas requirejs si la variable est l’argument plutôt que le type.

Concernant le commentaire de @ icepack: la possibilité ou la probabilité d’un changement de type par rapport au nom de variable n’est pas le problème. Imaginez que le nom de la variable soit utilisé comme argument de sizeof puis modifié ultérieurement. Dans le meilleur des cas, une opération de refactor-rename modifie toutes les occurrences et aucune erreur n’est introduite. Dans le pire des cas, une instance de sizeof est manquée et le compilateur se plaint et vous le corrigez. Si le type est modifié, vous avez terminé, aucune possibilité d’erreur dans les instructions sizeof.

Maintenant, imaginez que le type soit l’argument de sizeof. Si le type de la variable est modifié, il n’y a pas d’autre moyen que l’inspection de trouver toute la taille relative à cette variable. Vous pouvez effectuer une recherche, mais vous obtiendrez des résultats positifs pour toutes les utilisations sans rapport avec sizeof du même type. Si vous en manquez un, vous aurez un problème d’exécution dû à une différence de taille, ce qui est beaucoup plus difficile à trouver.

En plus de ce que Steve dit, permettez-moi d’append que sizeof n’évalue pas son opérande. Vous êtes donc libre de faire n’importe quoi. Non seulement vous pouvez utiliser des variables non encore initialisées, mais vous pouvez également déréférencer un pointeur nul, appeler des fonctions non définies mais seulement déclarées et effectuer d’autres types de tâches. Je vous encourage à toujours utiliser la version expression pour les raisons que Steve a grandement expliquées.

Notez également que les noms de types sont parfois très longs et illisibles, pensez simplement aux pointeurs sur les fonctions (en particulier en C ++). Au lieu d’écrire sizeof(my_long_type) vous ne faites que sizeof t .

Vous pouvez voir peu de différence entre ceux-ci:

 foo **ff = malloc(count * sizeof *ff); foo **gg = malloc(sizeof(foo*) * count); 

..mais que faire si l’allocation n’est pas à proximité de la déclaration? Si je rencontre une ligne comme celle-ci:

 ff = realloc(ff, count * sizeof *ff); 

alors je suis raisonnablement sûr que la ligne est correcte, sans même me rappeler le type de ff . Cependant, si je vois ceci:

 ff = realloc(ff, count * sizeof(foo *)); 

alors je pourrais être quelque peu méfiant et avoir besoin de rechercher le type de ff pour me rassurer.

Les lignes f et ff sont nettement pires que g et gg. sizeof f est la taille du pointeur, puisque f est un point. Pour les rendre équivalents, vous devez écrire sizeof *f (ou, pour une meilleure lisibilité, sizeof(*f) ).

J’ai tendance à utiliser sizeof(type) dans l’allocation de mémoire, mais invariablement sizeof(variable) lors de l’utilisation d’une variable locale ou globale. Néanmoins, il est sage de conseiller d’utiliser le nom de la variable tout le temps.

J’ai également eu une longue discussion (assez animée parfois et qui a duré plusieurs jours – nous avons fini par accepter de différer) sur la question de savoir s’il est acceptable d’utiliser sizeof(variable) ou s’il doit s’agir de sizeof variable ; En d’autres termes, est-il important que les parenthèses entourent l’argument de sizeof ? Je n’ai jamais rencontré de compilateur qui se préoccupe de sizeof(variable) , donc je privilégie l’uniformité et utilise toujours les parenthèses avec sizeof . Mon collègue a également insisté sur le fait que les parenthèses ne doivent pas être utilisées avec des variables; En quelque sorte, il existe / existait une distinction précieuse entre la notation avec et sans les parenthèses. Je n’ai pas été convaincu – je ne m’attends pas à être persuadé.

Sur un sharepoint vue totalement différent, quelques autres points à propos de sizeof :

  • Si vous utilisez C99 et VLA (tableaux de longueur variable), alors sizeof(vla) n’est pas une constante de compilation. Il faut se méfier!
  • Le pré-processeur C ne comprend pas la sizeof ce qui est gênant mais logique.

Prendre la taille d’une variable peut avoir des résultats inattendus. Lorsque la variable est un tableau, sizeof (tableau) renverra la taille du tableau, et non la taille d’un élément individuel ou la taille d’un pointeur. Prendre la taille d’un pointeur retournera la taille d’un pointeur. Mais comme les tableaux sont généralement représentés comme des pointeurs lorsqu’ils sont échangés, les choses peuvent devenir confuses.

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 avec un type particulier, choisissez sizeof(type) . Généralement, vous en avez besoin si vous avez une typedef qui définit de nombreuses variables que vous traitez différemment en fonction de leur type (par exemple, la sérialisation). Il est possible que vous ne sachiez pas laquelle de ces variables restra dans les futures versions de code. Le choix du type comme argument est donc logique. Même le changement d’une telle typedef n’affectera pas votre ligne sizeof .