Pergunta

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

Foi útil?

Solução

C não fornece serviços linguísticos de fazer isso -. Você tem que fazê-lo sozinho e comparar cada membro da estrutura pelo membro

Outras dicas

Você pode ser tentado a usar memcmp(&a, &b, sizeof(struct foo)), mas ele pode não funcionar em todas as situações. O compilador pode adicionar espaço tampão alinhamento a uma estrutura, e os valores encontrados em locais de memória deitado no espaço de buffer não são garantidos para ser qualquer valor particular.

Mas, se você usar calloc ou memset o tamanho total das estruturas antes de usá-los, você pode fazer um rasa comparação com memcmp (se a sua estrutura contém ponteiros, ele irá corresponder somente se o endereço os ponteiros estão a apontar para são os mesmos).

Se você fazê-lo muito Eu sugeriria escrevendo uma função que compara as duas estruturas. Dessa forma, se você mudar a estrutura que você só precisa mudar a comparar em um só lugar.

Quanto à forma de fazê-lo .... Você precisa comparar cada elemento individualmente

Você não pode usar memcmp para comparar estruturas para a igualdade devido a potenciais caracteres de preenchimento aleatório entre o campo em estruturas.

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

O código acima falhar por uma estrutura como esta:

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

Você tem que usar comparação membro-wise para ser seguro.

Note que você pode usar memcmp () no stuctures não estáticos, sem se preocupar com estofamento, contanto que você não Inicializar todos os membros (uma vez). Isso é definido por C90:

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

@ Greg está correta que se deve escrever funções comparação explícita no caso geral.

É possível usar memcmp se:

  • as estruturas não contêm campos de ponto flutuante que são possivelmente NaN.
  • as estruturas contêm nenhum preenchimento (uso -Wpadded com clang para verificar isso), ou o estruturas são explicitamente inicializado com memset na inicialização.
  • Não existem tipos de membros (como o Windows BOOL) que têm valores distintos, mas equivalentes.

A menos que você está programando para sistemas embarcados (ou escrevendo uma biblioteca que pode ser usado sobre eles), eu não iria se preocupar em alguns dos casos de canto no padrão C. O próximo vs. longe ponteiro distinção não existe em qualquer dispositivo de 32 ou 64 bits. No sistema não-incorporado que eu conheço tem vários ponteiros NULL.

Outra opção é auto gerar-as funções de igualdade. Se você colocar suas definições de struct de uma forma simples, é possível usar o processamento de texto simples para lidar com definições de struct simples. Você pode usar libclang para o caso geral -. Uma vez que utiliza a mesma interface como Clang, ele lida com todos os casos de canto corretamente (com exceção de bugs)

Eu não vi tal biblioteca de geração de código. No entanto, parece relativamente simples.

No entanto, também é o caso de que tais funções igualdade geradas muitas vezes fazer a coisa errada a nível da aplicação. Por exemplo, se duas estruturas UNICODE_STRING no Windows ser comparado superficialmente ou profundamente?

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

  1. São estas duas estruturas o mesmo objeto?
  2. Será que eles têm o mesmo valor?

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

No caso especial em que as estruturas não contêm ponteiros você pode fazer uma memcmp para executar uma comparação bit a bit dos dados contidos em cada sem ter de saber o que os meios de dados.

Certifique-se de que você sabe o que significa 'iguais' para cada membro - é óbvio para ints mas mais sutil quando se trata de valores de ponto flutuante ou tipos definidos pelo usuário

.

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

elemento Comparar por elemento é seguro e não falha.

Se as estruturas contêm apenas primitivas ou se você estiver interessado em igualdade estrita, em seguida, você pode fazer algo como isto:

int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs)
{
    return memcmp(lhs, rsh, sizeof(struct my_struct));
}

No entanto, se suas estruturas contêm ponteiros para outras estruturas ou uniões, então você terá que escrever uma função que compara os primitivos adequada e requer comparação make contra as outras estruturas conforme o caso.

Esteja ciente, no entanto, que você deve ter memset utilizado (& a, sizeof (struct my_struct), 1) para zerar o intervalo de memória das estruturas como parte de sua inicialização ADT.

Se as 2 estruturas variáveis ??são initialied com calloc ou eles são definidos com 0 por memset para que você possa comparar as suas 2 estruturas com memcmp e não há nenhuma preocupação sobre a estrutura de lixo e isso permitirá que você ganhe tempo

Este exemplo compatível usa o #pragma pacote de extensão do compilador do Microsoft Visual Studio para garantir que os membros da estrutura são embalados tão firmemente quanto possível:

#include <string.h>

#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))) {
    /* ... */
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top