sizeof style: sizeof (type) ou sizeof variable?

22

Eu já vi dois estilos de uso sizeofpara operações relacionadas à memória (como em memsetou malloc):

  • sizeof(type)e
  • sizeof variable ou sizeof(variable)

Qual deles você prefere, ou você usaria uma mistura dos dois estilos, e quando você usaria cada estilo? Quais são os prós e os contras de cada estilo e quando você os usa?

Como exemplo, posso ver o seguinte par de situações em que um estilo ajuda e o outro não:

Quando você errar o ponteiro indireto:

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

Quando o tipo muda:

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

Respostas:

30

Eu perco sizeof(variable)mais sizeof(type). Considerar:

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));

No primeiro caso, é fácil verificar se os tamanhos corretos estão sendo passados ​​para memset. No segundo caso, é necessário revisar constantemente as seções superior e inferior para garantir que você seja consistente.

vy32
fonte
4
Além disso, se você alterar o tipo da variável, o código que assume o tipo precisará ser alterado. Eu acho que é preferível codificar corretamente com a menor dependência possível do tipo. (Eu sou influenciado por um projeto de volta grande 16 bits para 32 conversão pouco durante o dia.)
Gort o robô
Isso é preferível para trabalhar com matrizes C, onde não é comum criar um typedef, mas use coisas como char array [MAX_SIZE];
mattnz
@ vy32: Errado 1: "sizeof (array) NÃO retorna o tamanho do array ... o tamanho do ponteiro para o array" - se arrayé de fato um array C, sizeof(array)retorna o número de bytes necessários para armazenar os elementos do array . Se arrayé um ponteiro para o primeiro elemento de uma matriz C deteriorada, sua declaração é válida. Passar uma matriz C como argumento de função faz com que pareça um ponteiro na função - todas as informações que provam que era uma matriz, como seu tamanho, são perdidas. É por isso que está deteriorado . Erro 2: "matrizes não existem realmente em C; ... simplesmente açúcar sintático para ponteiros".
Johann Gerell
9

A preferência (como sempre) é refletir sua intenção o mais diretamente possível.

A intenção é operar contra a memória de uma variável existente? sizeof(variable)Nesse caso, use , pois isso mostra o mais próximo possível que é da memória da variável em si que você se importa.

A intenção é realizar algum cálculo no tipo, por exemplo, para determinar quanta memória deve ser alocada para uma nova instância? Se sim, então use sizeof(type).

Ou seja, eu prefiro

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

sobre

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

como o último caso parece que você está tentando acessar uma variável que ainda não existe.

Por outro lado, eu prefiro

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

sobre

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

como a intenção é claramente preencher com zero o conteúdo da variável, é a variável na qual devemos operar. Tentar usar os metadados de tipo apenas confunde as coisas aqui.

Aidan Cully
fonte
Eu sempre faço, mas isso é uma questão de gosto pessoal. Considero que void *são automaticamente convertidos para outros tipos de ponteiros como uma característica incorreta.
Aidan Cully
3

Eu preferiria muito sizeof(type)mais sizeof variable. Mesmo que o obriga a se preocupar mais com o tipo e fazer mais mudanças, ele ajuda a evitar erros ponteiro indireç~ao, que estão entre a causa mais comum de erros em C .

Eu não me preocuparia tanto com bugs onde o tipo sizeof(type)é alterado; sempre que alterar o tipo de uma variável, faça uma varredura rápida para ver onde essa variável é usada e se é necessário alterar alguma sizeof(type)instrução. Embora sempre exista uma chance de errar, há um risco muito menor do que erros de indicação indireta.

Uma vantagem sizeof variableé para matrizes, mas, na prática, descobri que passar matrizes como pares de primeiro / len é muito mais comum (nesse caso, basta usar o comprimento), além disso, também é muito fácil errar o tamanho devido a deterioração da matriz / ponteiro, como neste exemplo:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}
congusbongus
fonte
2
"Verificação rápida para ver onde essa variável é usada ... sempre há uma chance de errar" - para mim, esse é o maior perigo de se fazer sizeof (type), e é por isso que sempre faço sizeof (variable). Como o resultado final desse perigo é que tudo ainda pode ser compilado e, mesmo se você cometer um erro, pode levar mais de um ano ou travamentos aleatórios e corrupção de buffer antes de detectá-lo. E não consegui fazer a conexão (obviamente, minha janela de tempo por pergunta é de cerca de 30 segundos) entre essa pergunta e "erros de indicação indireta".
DXM
@ DXM Com o operando sizeof, se é um valor, então é sizeof var; se é um ponteiro é sizeof *var. Isso também é algo que as pessoas podem errar, e o compilador o aceitará sem reclamar. Argumento que esses erros são muito mais difíceis de detectar e são mais comuns do que erros no sizeof(type)formulário.
congusbongus
1
Seus dois tipos C e tamanho de operador estão fundamentalmente quebrados e nunca serão confiáveis, nada que você faça como programador pode consertar.
mattnz
À medida que a postagem é marcada C, a publicação do código C é mais informativa do que o código C ++ mat3_t::mat3_t(...).
chux - Restabelece Monica 28/11
0

O objetivo é remover a redundância. Se você usar sizeof para uma operação relacionada a uma variável, obviamente você refletirá isso no sizeof. Sim, você pode errar como no primeiro exemplo, mas a cura não é do tipo use, mas * var, correspondendo corretamente ao objetivo.

Para mitigar esses problemas, é comum o uso de macros, modelos e ferramentas similares treinadas para o caso de uso, em vez do tamanho simples.

Veja minha macro CLEAR, usada exclusivamente em vez do memset nu. Salvei minha bunda várias vezes em casos de erro de digitação indireto ou quando um conteúdo struct pegou um vetor ou string ...

Balog Pal
fonte
Macros, como que são o que deu programação Macro do C um mau nome ......
mattnz
@mattnz: por favor, mostre a melhor alternativa. É a maneira mais fácil de falar coisas abstrato do que criar programas realmente trabalho
Balog Pal
1
A macro vinculada é C ++, e este post tem a tag 'C' (são idiomas diferentes), Ada seria minha sugestão.
mattnz
@mattnz: e o mesmo tópico mostra como aplicar de maneira semelhante para C. Parece que você perdeu completamente o objetivo, que não é a implementação real do conteúdo, mas o uso mais seguro em comparação às matérias-primas. Btw maneiras legíveis também.
quer
0

A lógica de negócios define sua escolha.

  1. Se seu código se refere a uma variável específica e sem essa variável, seu código não faz sentido - escolha sizeof(var)

  2. Se você codificar lida com um conjunto de variáveis ​​com um tipo específico - escolha sizeof(type). Normalmente, você precisa disso se tiver um typedefque define muitas variáveis ​​que você processa de maneira diferente com base em seu tipo (por exemplo, serialização). Você pode não saber quais dessas variáveis ​​permanecerão em futuras versões de código, portanto, escolher o tipo como argumento é logicamente correto. Mesmo alterar isso typedefnão afetará seu tamanho da linha.

Riga
fonte
-1

Dependendo do tamanho da finalidade (variável), pode ser a melhor solução. Dessa forma, você pode alterar seu tipo de variável, se necessário, sem corrigir todas as entradas para o tipo. Mas, novamente, isso depende do seu objetivo.

Pedro Perez
fonte