¿Por qué C no proporciona la comparación de estructuras?

Como la mayoría de los progtwigdores de C saben, no puedes comparar directamente dos estructuras.

Considerar:

void isequal(MY_STRUCT a, MY_STRUCT b) { if (a == b) { puts("equal"); } else { puts("not equal"); } } 

La comparación a a==b hará que AFAIK genere un error de comstackción en cualquier comstackdor C sensible, porque el estándar C no permite la comparación de estructuras incorporada. Las soluciones alternativas con memcmp son, por supuesto, una mala idea debido a la alineación, el empaquetado, los campos de bits, etc., por lo que terminamos escribiendo funciones de comparación elemento por elemento.

Por otro lado, SÍ permite la asignación de estructuras, por ejemplo, a = b es totalmente legal. Claramente, el comstackdor puede lidiar con eso de manera bastante trivial, entonces ¿por qué no compararlo?

La única idea que tuve fue que la asignación de la estructura es probablemente bastante cercana a memcpy (), ya que las brechas debidas a la alineación, etc. no importan. Por otro lado, una comparación podría ser más complicada. ¿O es esto algo que me falta?

Obviamente, soy consciente de que hacer una comparación simple elemento por elemento no es necesariamente suficiente, por ejemplo, si la estructura contiene un puntero a una cadena, pero hay circunstancias en las que sería útil.

Como han mencionado otros, aquí hay un extracto de C: A Reference Manual de Harbison y Steele:

Las estructuras y los sindicatos no se pueden comparar por la igualdad, aunque se permita la asignación de estos tipos. Las brechas en estructuras y uniones causadas por restricciones de alineación podrían contener valores arbitrarios, y compensar esto impondría una sobrecarga inaceptable en la comparación de igualdad o en todas las operaciones que modificaron la estructura y los tipos de unión.

La comparación no es compatible por la misma razón por la que memcmp falla.

Debido a los campos de relleno, la comparación fallaría de manera impredecible, lo que sería inaceptable para la mayoría de los progtwigdores. La asignación cambia los campos de relleno invisibles, pero estos son invisibles de todos modos, por lo que no hay nada inesperado allí.

Obviamente, puede preguntar: ¿por qué no rellena todos los campos de relleno? Seguro que funcionaría, pero también haría que todos los progtwigs paguen por algo que quizás no necesiten.

EDITAR

Oli Charlesworth señala en los comentarios que puede estar preguntando: “por qué el comstackdor no genera código para la comparación miembro por miembro”. Si ese es el caso, debo confesar: No sé :-). El comstackdor tendría toda la información necesaria si solo permitiera comparar tipos completos.

El operador de comparación de generación automática es una mala idea. Imagina cómo funcionaría la comparación para esta estructura:

 struct s1 { int len; char str[100]; }; 

Esta es una cuerda tipo pascal con una longitud máxima de 100.

Otro caso

 struct s2 { char a[100]; } 

¿Cómo puede el comstackdor saber cómo comparar un campo? Si esta es una cadena terminada en NUL, el comstackdor debe usar strcmp o strncmp. Si este es el comstackdor char array, debe usar memcmp.

Encontré esto en la justificación C ( justificación C99 V5.10 ), 6.5.9:

El Comité C89 consideró, en más de una ocasión, permitir la comparación de estructuras para la igualdad. Tales propuestas fracasaron en el problema de los agujeros en las estructuras. Una comparación de dos estructuras de bytes requerirá que los orificios se establezcan en cero para que todos los orificios se comparen de igual manera, una tarea difícil para las variables asignadas de forma automática o dinámica.

La posibilidad de elementos de tipo sindical en una estructura plantea problemas insuperables con este enfoque. Sin la seguridad de que todos los orificios se establecieron en cero, la implementación tendría que estar preparada para dividir una comparación de estructura en un número arbitrario de comparaciones de miembros; por lo tanto, una expresión aparentemente simple podría expandirse en una extensión sustancial de código, lo cual es contrario al espíritu de C

En un lenguaje sencillo: dado que las estructuras / uniones pueden contener bytes de relleno, y el comité no las aplicó para mantener ciertos valores, no implementarían esta característica. Porque si todos los bytes de relleno se deben establecer en cero, se requeriría una sobrecarga adicional en tiempo de ejecución.

Para agregar a las buenas respuestas existentes:

 struct foo { union { uint32_t i; float f; } u; } a, b; auf = -0.0; buf = 0.0; if (a==b) // what to do?! 

El problema surge inherentemente de que las uniones no pueden almacenar / rastrear qué miembro está actualizado.