Como você compara duas instâncias de estruturas para igualdade no padrão C?
216
C não fornece recursos de idioma para fazer isso - você precisa fazer isso sozinho e comparar cada membro da estrutura por membro.
0.0, -0.0 NaN
é um problemamemcmp()
. Ponteiros que diferem na representação binária podem apontar para o mesmo local (por exemplo, DOS: seg: offset) e, portanto, são iguais. Alguns sistemas têm vários ponteiros nulos que se comparam igualmente. O mesmo para obscuroint
com os tipos -0 e ponto flutuante com codificações redundantes. (Intel long double, decimal64, etc.) Esses problemas não fazem diferença, sãocalloc()
usados ou não, ou preenchimento.==
não está trabalhando com estruturas (como eu), consulte stackoverflow.com/questions/46995631/…Você pode ser tentado a usar
memcmp(&a, &b, sizeof(struct foo))
, mas pode não funcionar em todas as situações. O compilador pode adicionar espaço de buffer de alinhamento a uma estrutura, e não é garantido que os valores encontrados nos locais de memória no espaço de buffer tenham um valor específico.Porém, se você usar
calloc
oumemset
o tamanho total das estruturas antes de usá-las, poderá fazer uma comparação superficial commemcmp
(se sua estrutura contiver ponteiros, ela corresponderá apenas se o endereço apontado pelos ponteiros for o mesmo).fonte
memcmp
condição de que a memória foi limpa primeiro. O que está quase funcionando, mas não está correto. Muitas vezes, a questão também não define "igualdade"; portanto, se você entender "igualdade de bytes da representação do objeto",memcmp
fará exatamente isso (se a memória está limpa ou não).Se você fizer muito isso, sugiro escrever uma função que compare as duas estruturas. Dessa forma, se você alterar a estrutura, precisará alterar apenas a comparação em um único local.
Quanto a como fazê-lo .... Você precisa comparar todos os elementos individualmente
fonte
Você não pode usar o memcmp para comparar estruturas de igualdade devido a caracteres de preenchimento aleatório em potencial entre campos em estruturas.
O exemplo acima falharia em uma estrutura como esta:
Você precisa usar a comparação entre membros para estar seguro.
fonte
@Greg está correto em que é necessário escrever funções de comparação explícitas no caso geral.
É possível usar
memcmp
se:NaN
.-Wpadded
com clang para verificar isso) OU as estruturas são explicitamente inicializadasmemset
na inicialização.BOOL
) que tenham valores distintos, mas equivalentes.A menos que você esteja programando para sistemas incorporados (ou escrevendo uma biblioteca que possa ser usada neles), eu não me preocuparia com alguns dos casos de canto no padrão C. A distinção entre ponteiro versus ponto distante não existe em nenhum dispositivo de 32 ou 64 bits. Nenhum sistema não incorporado que eu conheço possui vários
NULL
ponteiros.Outra opção é gerar automaticamente as funções de igualdade. Se você definir suas definições de estrutura de uma maneira simples, é possível usar um processamento de texto simples para lidar com definições simples de estrutura. Você pode usar libclang para o caso geral - uma vez que usa o mesmo front-end que o Clang, ele lida com todos os casos de canto corretamente (exceto erros).
Eu não vi essa biblioteca de geração de código. No entanto, parece relativamente simples.
No entanto, também é o caso de que tais funções de igualdade geradas frequentemente façam a coisa errada no nível do aplicativo. Por exemplo, duas
UNICODE_STRING
estruturas no Windows devem ser comparadas superficial ou profundamente?fonte
memset
, etc., não garante o valor dos bits de preenchimento após mais de escrita para um elemento de estrutura, consulte: stackoverflow.com/q/52684192/689161Observe que você pode usar o memcmp () em estruturas não estáticas sem se preocupar com preenchimento, desde que não inicialize todos os membros (de uma só vez). Isso é definido por C90:
http://www.pixelbeat.org/programming/gcc/auto_init.html
fonte
{0, }
também zerará quaisquer bytes de preenchimento?Depende se a pergunta que você está fazendo é:
Para descobrir se eles são o mesmo objeto, compare os ponteiros com as duas estruturas de igualdade. Se você deseja descobrir em geral se eles têm o mesmo valor, é necessário fazer uma comparação profunda. Isso envolve comparar todos os membros. Se os membros forem ponteiros para outras estruturas, você também precisará recursá-las.
No caso especial em que as estruturas não contêm ponteiros, você pode executar um memcmp para realizar uma comparação bit a bit dos dados contidos em cada uma, sem precisar saber o que os dados significam.
Certifique-se de saber o que 'igual' significa para cada membro - é óbvio para ints, mas mais sutil quando se trata de valores de ponto flutuante ou tipos definidos pelo usuário.
fonte
memcmp
não compara estrutura,memcmp
compara o binário e sempre há lixo na estrutura; portanto, sempre sai falso em comparação.Compare elemento por elemento, é seguro e não falha.
fonte
Se as estruturas contiverem apenas primitivas ou se você estiver interessado em igualdade estrita, poderá fazer algo assim:
No entanto, se suas estruturas contiverem ponteiros para outras estruturas ou uniões, será necessário escrever uma função que compare os primitivos corretamente e faça chamadas de comparação com as outras estruturas, conforme apropriado.
Lembre-se, no entanto, de que você deve ter usado o memset (& a, sizeof (struct my_struct), 1) para zerar o intervalo de memória das estruturas como parte da inicialização do ADT.
fonte
se a variável 2 estruturas for inicializada com calloc ou for definida com 0 pelo memset, você poderá comparar suas 2 estruturas com o memcmp e não haverá preocupação com o lixo da estrutura, o que permitirá ganhar tempo
fonte
Este exemplo compatível usa a extensão do compilador #pragma pack do Microsoft Visual Studio para garantir que os membros da estrutura sejam compactados da maneira mais rígida possível:
fonte