开发者

Why doesn't C provide struct comparison?

As most C programmers know, you can't directly compare two structures.

Consider:

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

The a==b comparison will AFAIK throw a compile error on any sensible C compiler, because the C standard doesn't allow for built-in structure comparison. Workarounds using memcmp are of course a bad idea due to alignment, packing, bitfields etc., so we end up writing element by element comparison functions.

On the other hand it DOES allow for structure assignment e.g. 开发者_运维知识库a = b is entirely legal. Clearly the compiler can cope with that fairly trivially, so why not comparison?

The only idea I had was that structure assignment is probably fairly close to memcpy(), as the gaps due to alignment etc. don't matter. On the other hand, a comparison might be more complicated. Or is this something I'm missing?

Obviously, I'm aware that doing a simple element by element comparison isn't necessarily enough, e.g. if the structure contains a pointer to a string, but there are circumstances where it would be useful.


As others have mentioned, here's an extract from C: A Reference Manual by Harbison and Steele:

Structures and unions cannot be compared for equality, even though assignment for these types is allowed. The gaps in structures and unions caused by alignment restrictions could contain arbitrary values, and compensating for this would impose an unacceptable overhead on the equality comparison or on all operations that modified structure and union types.


Comparison is unsupported for the same reason memcmp fails.

Due to padding fields the comparison would fail in unpredictable ways which would be unacceptable for most programmers. Assignment changes the invisible padding fields, but these are invisible anyway, so nothing unexpected there.

Obviously, you may ask: so why doesn't it just zero-fill all the padding fields ? Sure that would work but it would also make all programs pay for something they might not need.

EDIT

Oli Charlesworth notes in the comments that you may be asking: "why doesn't the compiler generate code for member-by-member comparison". If that is the case, I must confess: I don't know :-). The compiler would have all the needed information if it would only allow comparing complete types.


I found this in the C rationale (C99 rationale V5.10), 6.5.9:

The C89 Committee considered, on more than one occasion, permitting comparison of structures for equality. Such proposals foundered on the problem of holes in structures. A byte-wise comparison of two structures would require that the holes assuredly be set to zero so that all holes would compare equal, a difficult task for automatic or dynamically allocated variables.

The possibility of union-type elements in a structure raises insuperable problems with this approach. Without the assurance that all holes were set to zero, the implementation would have to be prepared to break a structure comparison into an arbitrary number of member comparisons; a seemingly simple expression could thus expand into a substantial stretch of code, which is contrary to the spirit of C

In plain English: Since structs/unions may contain padding bytes, and the committee had not enforced these to hold certain values, they wouldn't implement this feature. Because if all padding bytes must be set to zero, it would require additional run-time overhead.


Auto-generate comparison operator is bad idea. Imagine how comparison would work for this structure:

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

This is pascal like string with maximum length 100

Another case

struct s2 {
   char a[100];
}

How can the compiler know how to compare a field? If this is a NUL-terminated string, the compiler must use strcmp or strncmp. If this is char array compiler must use memcmp.


To add to the existing good answers:

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

The problem arises inherently from unions not being able to store/track which member is current.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜