Pregunta

¿Cómo compara dos instancias de estructuras para la igualdad en el estándar C?

¿Fue útil?

Solución

C no proporciona medios de lenguaje para hacer esto, usted debe hacerlo usted mismo y comparar cada miembro de la estructura.

Otros consejos

Puede sentirse tentado a utilizar memcmp (& amp; a, & amp; b, sizeof (struct foo)) , pero es posible que no funcione en todas las situaciones. El compilador puede agregar espacio de búfer de alineación a una estructura, y no se garantiza que los valores encontrados en las ubicaciones de memoria que se encuentran en el espacio del búfer tengan un valor en particular.

Pero, si usas calloc o memset del tamaño completo de las estructuras antes de usarlas, puedes hacer un superficial comparación con memcmp (si su estructura contiene punteros, coincidirá solo si la dirección a la que apuntan los punteros es la misma).

Si lo haces mucho, sugeriría escribir una función que compare las dos estructuras. De esa manera, si alguna vez cambia la estructura, solo necesita cambiar la comparación en un solo lugar.

En cuanto a cómo hacerlo ... Necesita comparar cada elemento individualmente

No puedes usar memcmp para comparar estructuras por igualdad debido a posibles caracteres de relleno aleatorios entre los campos en las estructuras.

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

Lo anterior fallaría para una estructura como esta:

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

Tienes que usar la comparación de miembros para estar seguro.

Tenga en cuenta que puede usar memcmp () en estructuras no estáticas sin preocuparse por el relleno, siempre y cuando no se inicialice todos los miembros (a la vez). Esto está definido por C90:

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

@Greg tiene razón en que uno debe escribir funciones de comparación explícitas en el caso general.

Es posible usar memcmp si:

  • las estructuras no contienen campos de punto flotante que posiblemente sean NaN .
  • las estructuras no contienen relleno (use -Wpadded con clang para verificar esto) O las estructuras se inicializan explícitamente con memset en la inicialización.
  • no hay tipos de miembros (como BOOL de Windows) que tengan valores distintos pero equivalentes.

A menos que esté programando para sistemas embebidos (o escribiendo una biblioteca que pueda usarse en ellos), no me preocuparía por algunos de los casos de esquina en el estándar C. La distinción entre el puntero cercano y el lejano no existe en ningún dispositivo de 32 o 64 bits. Ningún sistema no integrado que conozco tiene múltiples punteros NULL .

Otra opción es generar automáticamente las funciones de igualdad. Si establece las definiciones de estructura de una manera sencilla, es posible utilizar el procesamiento de texto simple para manejar las definiciones de estructura simples. Puedes usar libclang para el caso general, ya que usa la misma interfaz que Clang, maneja todos los casos de esquina correctamente (salvo los errores).

No he visto tal biblioteca de generación de código. Sin embargo, parece relativamente simple.

Sin embargo, también es cierto que tales funciones de igualdad generadas a menudo hacen lo incorrecto a nivel de aplicación. Por ejemplo, ¿deberían compararse dos estructuras UNICODE_STRING en Windows de manera superficial o profunda?

Depende de si la pregunta que está haciendo es:

  1. ¿Son estas dos estructuras el mismo objeto?
  2. ¿Tienen el mismo valor?

Para averiguar si son el mismo objeto, compare los punteros a las dos estructuras para la igualdad. Si desea averiguar en general si tienen el mismo valor, debe hacer una comparación profunda. Esto implica comparar a todos los miembros. Si los miembros son punteros a otras estructuras, también debe recurrir a esas estructuras.

En el caso especial donde las estructuras no contienen punteros, puede hacer un memcmp para realizar una comparación a nivel de bits de los datos contenidos en cada uno sin tener que saber qué significan los datos.

Asegúrese de saber qué significa "igual a" para cada miembro; es obvio para los ints pero más sutil cuando se trata de valores de punto flotante o tipos definidos por el usuario.

memcmp no compara la estructura, memcmp compara el binario, y siempre hay basura en la estructura, por lo que siempre sale Falso en comparación.

Comparar elemento por elemento es seguro y no falla.

Si las estructuras solo contienen primitivas o si te interesa la igualdad estricta, puedes hacer algo como esto:

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

Sin embargo, si sus estructuras contienen punteros a otras estructuras o uniones, deberá escribir una función que compare las primitivas correctamente y realizar comparaciones con otras estructuras, según corresponda.

Sin embargo, tenga en cuenta que debería haber usado memset (& amp; a, sizeof (struct my_struct), 1) para poner a cero el rango de memoria de las estructuras como parte de su inicialización ADT.

si las variables de 2 estructuras se inician con calloc o están configuradas con 0 por memset para que pueda comparar sus 2 estructuras con memcmp y no se preocupe por la estructura de basura y esto le permitirá ganar tiempo

Este ejemplo compatible utiliza la extensión del compilador #pragma pack de Microsoft Visual Studio para garantizar que los miembros de la estructura estén empaquetados lo más estrechamente posible:

#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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top