'invalid operands to binary operands' 在比较两个并集时

'invalid operands to binary operands' while comparing two unions

我正在编写代码以在类型不可知的 C 中实现链表。这就是我想要做的。

  1. 创建一个可以存储以下任意一个的联合:int、char*、double、char。

    union element { int num; char* str; double real; char alph; };

  2. 用于跟踪联合存储的元素的枚举。

    enum { NUM, STR, REAL, CHAR };

  3. 将存储节点值的结构。

    struct node { int type; union element data; struct node *next; };

  4. 因为我可能有多个列表,我还为节点创建了一个容器,

    struct list { struct node *head; };

现在我想创建一个函数来从列表中获取一个元素。函数是,

node* findkey(list *l, union element key)
{
    node *i=list->head;
    while(!i) {
        if(i->data == key) {
            return i;
        i=i->next;
    }
    return NULL;
}

当我编译代码时,clang 抛出这个错误,

linkedlist.c:33:11: error: invalid operands to binary expression ('union element' and
      'union element')
                if(i->data == key)
                   ~~~~ ^  ~~~
1 error generated.

这里

if(i->data == key) {

它比较联合变量,如 Harbison and Steele book

中所述无效

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.

你可以比较工会成员喜欢

if(i->data.num == key.num) {
 /*  some code */    
}

已将其移至答案,因为它不再适合发表评论。

问题的根本原因是,如果联合成员的大小不同,如果写入较小的成员然后比较较大的成员,则无法保证比较成功。例如,如果您写给两个联合的 alph 成员,然后比较 num 成员,保存 alph 的一个字节将正确比较,但即使它们相等,num 中的剩余字节可能不同,导致 "false unequal" 结果。与写入 num 成员然后比较 real 成员相同。

所以为了避免这个问题,你需要先比较两个 type 值,只有当它们匹配时才比较合适的联合成员对。选择要比较的成员最容易通过开关完成。

node* findkey(list *l, union element key, int type)
{
    node *i=list->head;
    while(!i) {
        // compare types first, assume no match if they differ
        if(i->type != type) {
            continue
        }
        switch (type)
        {
        case NUM:
            if(i->data.num == key.num) {
                return i;
            }
            break;
        case STR:
            ...
        case REAL:
            ...
        case CHAR:
            ...
        }
        i=i->next;
    }
    return NULL;
}

我将添加一条注释,您如何处理 case STR: 取决于您想要的行为。如果您希望两个字符串匹配,请使用 strcmp() 如果您希望它们引用相同的字符串,请在两个指针上使用 ==。我怀疑前者将是一种更有用的做事方式,但值得注意的是精确的指针比较。有点类似于PHP.

=====的区别