표준 C에서 두 개의 구조체 인스턴스가 동일한 지 어떻게 비교합니까?
표준 C에서 두 개의 구조체 인스턴스가 동일한 지 어떻게 비교합니까?
답변:
C는이를 위해 언어 기능을 제공하지 않습니다.이를 직접 수행하고 각 구조 구성원을 구성원별로 비교해야합니다.
0.0, -0.0 NaN
는 문제가 memcmp()
있습니다. 이진 표현이 다른 포인터는 동일한 위치 (예 : DOS : seg : offset)를 가리킬 수 있으므로 동일합니다. 일부 시스템에는 동일하게 비교되는 여러 개의 널 포인터가 있습니다. int
중복 인코딩이있는 -0 및 부동 소수점 유형의 경우 모호한 경우 와 동일합니다 . (Intel long double, decimal64 등)이 문제는 calloc()
사용되거나 패딩되지 않습니다.
==
나와 같은 구조로 작업하지 않는지 궁금한 경우 stackoverflow.com/questions/46995631/…
을 사용 memcmp(&a, &b, sizeof(struct foo))
하고 싶을 수도 있지만 모든 상황에서 작동하지 않을 수 있습니다. 컴파일러는 정렬 버퍼 공간을 구조에 추가 할 수 있으며 버퍼 공간에있는 메모리 위치에서 발견 된 값은 특정 값으로 보장되지 않습니다.
그러나 구조를 사용하기 전에 calloc
또는 memset
전체 크기를 사용하는 경우 구조 와 포인터를 비교할 때 얕은 비교를 수행 할 수 있습니다 (구조에 포인터가 포함 된 경우 포인터가 가리키는 주소가 동일한 경우에만 일치 함).memcmp
memcmp
메모리가 먼저 지워졌다면 얕은 비교를 할 수 있다고 말합니다 . 작동에 가깝지만 올바르지 않습니다. 종종 질문은 "평등"을 정의하지 않으므로 "객체 표현의 바이트 단위 평등"을 의미 memcmp
하는 경우 메모리가 지워 졌는지 여부에 관계없이 정확하게 수행됩니다.
구조체의 필드 사이에 잠재적 인 임의의 패딩 문자로 인해 구조체의 동등성을 비교하기 위해 memcmp를 사용할 수 없습니다.
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
위와 같은 구조체에서는 위의 내용이 실패합니다.
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
안전을 위해 멤버 별 비교를 사용해야합니다.
@Greg는 일반적인 경우 명시적인 비교 함수를 작성해야합니다.
다음과 같은 memcmp
경우 에 사용할 수 있습니다.
NaN
.-Wpadded
clang을 사용 하여이를 확인) 구조체를 초기화 할 memset
때 명시 적으로 초기화합니다.BOOL
고유하지만 동등한 값을 갖는 멤버 유형 (예 : Windows )이 없습니다.임베디드 시스템을 프로그래밍하거나 (또는 그에 사용될 라이브러리를 작성하지 않는 한) C 표준의 일부 경우에 대해 걱정하지 않을 것입니다. 근거리 포인터와 원거리 포인터 구별은 32 비트 또는 64 비트 장치에 존재하지 않습니다. 내가 아는 내장형 시스템에는 여러 개의 NULL
포인터가 없습니다.
다른 옵션은 등식 함수를 자동 생성하는 것입니다. 구조체 정의를 간단한 방법으로 배치하면 간단한 텍스트 처리를 사용하여 간단한 구조체 정의를 처리 할 수 있습니다. 일반적인 경우에는 libclang을 사용할 수 있습니다. Clang과 동일한 프런트 엔드를 사용하기 때문에 모든 코너 경우를 올바르게 처리합니다 (버그 제외).
그런 코드 생성 라이브러리를 보지 못했습니다. 그러나 비교적 단순 해 보입니다.
그러나 이와 같이 생성 된 등식 함수가 종종 응용 프로그램 레벨에서 잘못된 일을하는 경우도 있습니다. 예를 들어, UNICODE_STRING
Windows에서 두 개의 구조체를 얕게 또는 깊게 비교 해야 합니까?
memset
등으로 구조체를 명시 적으로 초기화 한다고해서 struct 요소에 추가로 쓴 후 패딩 비트의 값을 보장 할 수는 없습니다. stackoverflow.com/q/52684192/689161
모든 멤버를 한 번에 초기화하지 않는 한 패딩에 대해 걱정하지 않고 정적이 아닌 구조에서 memcmp ()를 사용할 수 있습니다. 이것은 C90에 의해 정의됩니다.
{0, }
패딩 바이트도 0으로 지정하는 것이 실제로 지정 되었습니까?
묻는 질문에 따라 다릅니다.
이들이 동일한 객체인지 확인하려면 두 구조체의 포인터가 동일한 지 비교하십시오. 값이 같은지 일반적으로 찾으려면 깊은 비교를해야합니다. 여기에는 모든 멤버를 비교하는 것이 포함됩니다. 멤버가 다른 구조체에 대한 포인터 인 경우 해당 구조체에도 재귀가 필요합니다.
구조체에 포인터가없는 특수한 경우 memcmp를 수행하여 데이터의 의미를 알 필요없이 각각에 포함 된 데이터를 비트 단위로 비교할 수 있습니다.
각 멤버에 대해 '같음'이 무엇을 의미하는지 알아야합니다. int에게는 분명하지만 부동 소수점 값 또는 사용자 정의 형식에 대해서는 더 미묘합니다.
구조체에 프리미티브 만 포함되거나 엄격한 평등에 관심이 있다면 다음과 같이 할 수 있습니다.
int my_struct_cmp (const struct my_struct * lhs, const struct my_struct * rhs) { memcmp (lhs, rsh, sizeof (struct my_struct))를 반환; }
그러나 구조체에 다른 구조체 또는 공용체에 대한 포인터가 포함 된 경우 프리미티브를 올바르게 비교하고 다른 구조와 비교하여 적절하게 비교하는 함수를 작성해야합니다.
그러나 ADT 초기화의 일부로 memset (& a, sizeof (struct my_struct), 1)을 사용하여 구조의 메모리 범위를 0으로 설정해야합니다.
이 호환 예제는 Microsoft Visual Studio의 #pragma pack 컴파일러 확장을 사용하여 구조 멤버를 최대한 단단히 패킹합니다.
#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))) {
/* ... */
}
}