Existem desvantagens em passar estruturas por valor em C, em vez de passar um ponteiro?
Se a estrutura é grande, obviamente existe o aspecto de desempenho de copiar muitos dados, mas para uma estrutura menor, deve basicamente ser o mesmo que passar vários valores para uma função.
Talvez seja ainda mais interessante quando usado como valores de retorno. C possui apenas valores de retorno únicos de funções, mas muitas vezes você precisa de vários. Portanto, uma solução simples é colocá-los em uma estrutura e retornar isso.
Existem razões a favor ou contra isso?
Como pode não ser óbvio para todos do que estou falando aqui, darei um exemplo simples.
Se estiver programando em C, mais cedo ou mais tarde você começará a escrever funções parecidas com esta:
void examine_data(const char *ptr, size_t len)
{
...
}
char *p = ...;
size_t l = ...;
examine_data(p, l);
Isto não é um problema. O único problema é que você precisa concordar com seu colega de trabalho na ordem em que os parâmetros devem ser, para que você use a mesma convenção em todas as funções.
Mas o que acontece quando você deseja retornar o mesmo tipo de informação? Você normalmente recebe algo parecido com isto:
char *get_data(size_t *len);
{
...
*len = ...datalen...;
return ...data...;
}
size_t len;
char *p = get_data(&len);
Isso funciona bem, mas é muito mais problemático. Um valor de retorno é um valor de retorno, exceto que nesta implementação não é. Não há como dizer, acima, que a função get_data não tem permissão para ver o que len aponta. E não há nada que faça o compilador verificar se um valor é realmente retornado por esse ponteiro. Então, no próximo mês, quando alguém modificar o código sem entendê-lo corretamente (porque ele não leu a documentação?), Ele será quebrado sem que ninguém perceba, ou começa a falhar aleatoriamente.
Então, a solução que proponho é a estrutura simples
struct blob { char *ptr; size_t len; }
Os exemplos podem ser reescritos assim:
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();
Por alguma razão, acho que a maioria das pessoas instintivamente faria o examine_data levar um ponteiro para um blob de estrutura, mas não vejo o porquê. Ainda recebe um ponteiro e um número inteiro, é muito mais claro que eles andam juntos. E, no caso get_data, é impossível errar da maneira que descrevi antes, pois não há valor de entrada para o comprimento e deve haver um comprimento retornado.
gettimeofday
) usam ponteiros, e as pessoas tomam isso como exemplo.
void examine data(const struct blob)
está incorreto.