«недопустимые операнды в двоичные операнды» при сравнении двух объединений - PullRequest
0 голосов
/ 10 сентября 2018

Я пишу код для реализации связанного списка в 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.

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

Перенес это в ответ, так как он больше не подходит для комментариев.

Основная причина проблемы заключается в том, что если члены объединения имеют разные размеры, вам не гарантируется, что сравнение будет успешным, если записать в меньшие элементы, но затем сравнить более крупные элементы. Например, если вы записали в alph член обоих объединений, но затем сравнили num членов, один байт, содержащий alph, будет сравниваться правильно, но даже если они равны, остальные байты в num может отличаться, что приводит к «ложному неравному» результату. То же самое с записью 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.

0 голосов
/ 10 сентября 2018

Здесь

if(i->data == key) {

переменная объединения, которая недействительна, как сказано в Книга Харбисона и Стила

Структуры и союзов не могут сравниваться для равенства , даже если присваивание для этих типов разрешено. Пробелы в структурах и Союзы, вызванные ограничениями выравнивания, могут содержать произвольные значения, и компенсация за это наложит неприемлемо накладные расходы на сравнение равенства или на все операции, которые изменили структура и типы объединения.

Вы можете сравнить членов профсоюза как

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