Y a-t-il des inconvénients à passer des structures par valeur en C, plutôt que de passer un pointeur?
Si la structure est grande, il y a évidemment l'aspect performant de la copie de beaucoup de données, mais pour une structure plus petite, cela devrait être fondamentalement la même chose que de passer plusieurs valeurs à une fonction.
C'est peut-être encore plus intéressant lorsqu'il est utilisé comme valeur de retour. C n'a qu'une seule valeur de retour des fonctions, mais vous en avez souvent besoin. Une solution simple consiste donc à les mettre dans une structure et à la renvoyer.
Y a-t-il des raisons pour ou contre cela?
Puisque ce dont je parle ici n'est peut-être pas évident pour tout le monde, je vais donner un exemple simple.
Si vous programmez en C, vous commencerez tôt ou tard à écrire des fonctions qui ressemblent à ceci:
void examine_data(const char *ptr, size_t len)
{
...
}
char *p = ...;
size_t l = ...;
examine_data(p, l);
Ce n'est pas un problème. Le seul problème est que vous devez convenir avec votre collègue de l'ordre dans lequel les paramètres doivent être afin d'utiliser la même convention dans toutes les fonctions.
Mais que se passe-t-il lorsque vous souhaitez renvoyer le même type d'informations? Vous obtenez généralement quelque chose comme ceci:
char *get_data(size_t *len);
{
...
*len = ...datalen...;
return ...data...;
}
size_t len;
char *p = get_data(&len);
Cela fonctionne bien, mais est beaucoup plus problématique. Une valeur de retour est une valeur de retour, sauf que dans cette implémentation, ce n'est pas le cas. Il n'y a aucun moyen de dire à partir de ce qui précède que la fonction get_data n'est pas autorisée à regarder vers quoi pointe len. Et rien ne permet au compilateur de vérifier qu'une valeur est effectivement renvoyée via ce pointeur. Donc le mois prochain, quand quelqu'un d'autre modifie le code sans le comprendre correctement (parce qu'il n'a pas lu la documentation?), Il est cassé sans que personne ne s'en aperçoive, ou il commence à planter au hasard.
Donc, la solution que je propose est la structure simple
struct blob { char *ptr; size_t len; }
Les exemples peuvent être réécrits comme ceci:
void examine_data(const struct blob data)
{
... use data.tr and data.len ...
}
struct blob = { .ptr = ..., .len = ... };
examine_data(blob);
struct blob get_data(void);
{
...
return (struct blob){ .ptr = ...data..., .len = ...len... };
}
struct blob data = get_data();
Pour une raison quelconque, je pense que la plupart des gens feraient instinctivement examine_data prendre un pointeur vers un blob struct, mais je ne vois pas pourquoi. Il obtient toujours un pointeur et un entier, il est juste beaucoup plus clair qu'ils vont ensemble. Et dans le cas de get_data, il est impossible de gâcher la manière dont j'ai décrit précédemment, car il n'y a pas de valeur d'entrée pour la longueur, et il doit y avoir une longueur retournée.
gettimeofday
) utiliser des pointeurs à la place, et les gens prennent cela comme exemple.
void examine data(const struct blob)
c'est incorrect.