sentencia - switch programacion
¿Cómo se comparan las estructuras para la igualdad en C? (11)
¿Cómo se comparan dos instancias de estructuras para la igualdad en el estándar C?
@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 coma flotante que posiblemente sean
NaN
. - las estructuras no contienen relleno (use
-Wpadded
con clang para verificar esto) O las estructuras se inicializan explícitamente conmemset
en la inicialización. - no hay tipos de miembros (como Windows
BOOL
) que tengan valores distintos pero equivalentes.
A menos que esté programando para sistemas integrados (o escriba una biblioteca que pueda usarse en ellos), no me preocuparé 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 incorporado que conozco tiene múltiples punteros NULL
.
Otra opción es generar automáticamente las funciones de igualdad. Si establece sus definiciones de estructura de una manera simple, es posible utilizar el procesamiento de texto simple para manejar definiciones simples de estructuras. Puede usar libclang para el caso general, ya que usa la misma interfaz que Clang, maneja todos los casos de esquina correctamente (salvo errores).
No he visto una biblioteca de generación de código. Sin embargo, parece relativamente simple.
Sin embargo, también es el caso que tales funciones de igualdad generadas a menudo harían lo incorrecto a nivel de aplicación. Por ejemplo, ¿se deberían comparar superficialmente o profundamente dos estructuras UNICODE_STRING
en Windows?
C no proporciona servicios de idiomas para hacer esto; debe hacerlo usted mismo y comparar cada miembro de la estructura por miembro.
Depende de si la pregunta que hace es:
- ¿Son estas dos estructuras el mismo objeto?
- ¿Tienen el mismo valor?
Para saber 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 debes recurrir a esas estructuras.
En el caso especial donde las estructuras no contienen punteros, puede hacer un memcmp para realizar una comparación bit a bit de los datos contenidos en cada uno sin tener que saber qué significan los datos.
Asegúrese de saber qué significa "igual" para cada miembro; es obvio para los ints pero más sutil cuando se trata de valores de coma flotante o tipos definidos por el usuario.
Este ejemplo conforme utiliza la extensión del compilador de paquete #pragma de Microsoft Visual Studio para garantizar que los miembros de la estructura estén empaquetados lo más ajustadamente 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))) {
/* ... */
}
}
No puede usar memcmp para comparar las estructuras de igualdad debido a los posibles caracteres de relleno aleatorio entre el campo 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.
Puede sentirse tentado de usar memcmp(&a, &b, sizeof(struct foo))
, pero puede no funcionar 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 de búfer tengan un valor particular.
Pero, si usa calloc
o memset
del tamaño completo de las estructuras antes de usarlas, puede hacer una comparación superficial con memcmp
(si su estructura contiene punteros, solo coincidirá si la dirección a la que apuntan los punteros es la misma).
Si las estructuras solo contienen elementos primitivos o si está interesado en la igualdad estricta, puede 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, entonces necesitará escribir una función que compare las primitivas de manera adecuada y haga llamadas de comparación contra las otras estructuras, según corresponda.
Tenga en cuenta, sin embargo, que debería haber usado memset (& a, sizeof (struct my_struct), 1) para poner a cero el rango de memoria de las estructuras como parte de su inicialización de ADT.
Si lo haces mucho, te sugiero que escribas una función que compare las dos estructuras. De esta forma, si alguna vez cambia la estructura, solo necesita cambiar la comparación en un solo lugar.
En cuanto a cómo hacerlo ... Necesitas comparar cada elemento individualmente
Tenga en cuenta que puede usar memcmp () en estructuras no estáticas sin preocuparse por el relleno, siempre y cuando no inicialice todos los miembros (a la vez). Esto está definido por C90:
si las 2 estructuras variables se inicializan con calloc o se establecen con 0 por memset para que pueda comparar sus 2 estructuras con memcmp y no hay que preocuparse por la basura de estructura y esto le permitirá ganar tiempo
memcmp
no compara la estructura, memcmp
compara el binario, y siempre hay basura en la estructura, por lo tanto, siempre aparece False en comparación.
Comparar elemento por elemento es seguro y no falla.