Como você compara estruturas para igualdade em C?

Como você compara duas instâncias de estruturas para igualdade no padrão C?

C não oferece resources de linguagem para fazer isso – você tem que fazer isso sozinho e comparar cada membro da estrutura por membro.

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 os valores encontrados em locais de memory localizados no espaço de buffer não são garantidos para qualquer valor específico.

Mas, se você usar calloc ou memset no tamanho total das estruturas antes de usá-las, você pode fazer uma comparação superficial com memcmp (se sua estrutura contiver pointers, ela corresponderá somente se o endereço indicado pelos pointers for o mesmo).

Se você fizer isso muito, sugiro escrever uma function que compara as duas estruturas. Dessa forma, se você alterar a estrutura, só precisará alterar a comparação em um só lugar.

Quanto a como fazê-lo …. Você precisa comparar cada elemento individualmente

Você não pode usar o memcmp para comparar estruturas quanto à igualdade devido a possíveis caracteres de preenchimento random entre campos nas estruturas.

  // bad memcmp(&struct1, &struct2, sizeof(struct1)); 

O acima falharia para uma estrutura como esta:

 typedef struct Foo { char a; /* padding */ double d; /* padding */ char e; /* padding */ int f; } Foo ; 

Você tem que usar a comparação de membros para estar seguro.

Observe que você pode usar o memcmp () em estruturas não estáticas sem se preocupar com preenchimento, contanto que você não inicialize todos os membros (de uma só vez). Isso é definido pelo C90:

http://www.pixelbeat.org/programming/gcc/auto_init.html

@Greg está correto que é necessário escrever funções de comparação explícitas no caso geral.

É possível usar o memcmp se:

  • as estruturas não contêm campos de ponto flutuante que possivelmente são NaN .
  • as structs não contêm preenchimento (use -Wpadded com clang para verificar isso) OU as estruturas são inicializadas explicitamente com memset na boot.
  • não há nenhum tipo de membro (como o Windows BOOL ) que tenha valores distintos, mas equivalentes.

A menos que você esteja programando para sistemas embarcados (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 do ponteiro near vs far não existe em nenhum dispositivo de 32 ou 64 bits. Nenhum sistema não incorporado que conheço tem vários pointers NULL .

Outra opção é gerar automaticamente as funções de igualdade. Se você colocar suas definições de struct de maneira simples, é possível usar o processamento de texto simples para manipular definições de struct simples. Você pode usar libclang para o caso geral – já que ele usa o mesmo frontend que o Clang, ele lida com todos os casos de canto corretamente (bloqueando bugs).

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 essas funções de igualdade geradas geralmente fazem a coisa errada no nível do aplicativo. Por exemplo, duas estruturas UNICODE_STRING no Windows devem ser comparadas superficialmente ou profundamente?

memcmp não compara a estrutura, o memcmp compara o binário, e há sempre lixo na estrutura, portanto, sempre aparece Falso em comparação.

Compare elemento por elemento, é seguro e não falha.

Se as estruturas só contiverem primitivos ou se você estiver interessado em igualdade estrita, então você pode fazer algo parecido com isto:

 int my_struct_cmp (const struct minha_strução * lhs, const struct minha_strução * rhs)
 {
     Retornar memcmp (lhs, rsh, sizeof (struct minha_strução));
 }

No entanto, se suas estruturas contiverem pointers para outras estruturas ou uniões, será necessário escrever uma function que compare as primitivas corretamente e faça comparações com as outras estruturas, conforme apropriado.

Esteja ciente, no entanto, que você deve ter usado o memset (& a, sizeof (struct my_struct), 1) para zerar o intervalo de memory das estruturas como parte de sua boot do ADT.

Depende se a pergunta que você está fazendo é:

  1. Essas duas estruturas são o mesmo object?
  2. Eles têm o mesmo valor?

Para descobrir se eles são o mesmo object, compare pointers para as duas estruturas de igualdade. Se você quiser descobrir, em geral, se eles têm o mesmo valor, você deve fazer uma comparação profunda. Isso envolve a comparação de todos os membros. Se os membros são pointers para outras estruturas, você precisa recorrer a essas estruturas também.

No caso especial em que as estruturas não contêm pointers, é possível fazer uma memcmp para executar uma comparação bit a bit dos dados contidos em cada um, sem precisar saber o que os dados significam.

Certifique-se de saber o que ‘equals’ significa para cada membro – é óbvio para ints, mas mais sutil quando se trata de valores de ponto flutuante ou tipos definidos pelo usuário.

se a variável de 2 estruturas for iniciada com calloc ou elas forem configuradas com 0 por memset, então você pode comparar suas 2 estruturas com memcmp e não há nenhuma preocupação com o lixo de estrutura e isso permitirá que você ganhe tempo

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 melhor forma possível:

 #include  #pragma pack(push, 1) struct s { char c; int i; char buffer[13]; }; #pragma pack(pop) void compare(const struct s *left, const struct s *right) { if (0 == memcmp(left, right, sizeof(struct s))) { /* ... */ } }