разыменование указателя на неполный тип

Я видел много вопросов по этому поводу, но я собираюсь задать вопрос по-другому без конкретного кода. Есть ли способ ЛЕГКО определить, что делает тип неполным? В моем случае я использую чужой код, и я полностью уверен, что у меня неправильные заголовки, но (поскольку компьютеры делают это намного быстрее и лучше, чем человеческие глаза) есть ли способ заставить компилятор сказать , "Эй, вы думаете, что у вас есть тип X в строке 34, но на самом деле он отсутствует". Сама ошибка появляется только при назначении, что не очень полезно.


person nick    schedule 23.04.2010    source источник


Ответы (7)


На днях я видел вопрос, в котором кто-то случайно использовал неполный тип, указав что-то вроде

struct a {
    int q; 
}; 
struct A *x; 
x->q = 3;

Компилятор знал, что struct A была структурой, несмотря на то, что A была полностью неопределенной, благодаря ключевому слову struct.

Это было в C++, где такое использование struct нетипично (и, как оказалось, может привести к стрельбе по ногам). В C, если вы делаете

typedef struct a {
    ...
} a;

тогда вы можете использовать a в качестве имени типа и опустить struct позже. Это приведет к тому, что компилятор позже выдаст вам ошибку неопределенного идентификатора, а не неполный тип, если вы опечатаетесь в имени или забудете заголовок.

person Potatoswatter    schedule 23.04.2010

Другая возможная причина — косвенная ссылка. Если код ссылается на структуру, которая не включена в текущий c-файл, компилятор будет жаловаться.

a->b->c // ошибка, если b не включен в текущий файл c

person Steeven Li    schedule 01.03.2017

Что вы имеете в виду, ошибка появляется только при назначении? Например, в GCC без назначения:

int main() {
    struct blah *b = 0;
    *b; // this is line 6
}

incompletetype.c:6: error: dereferencing pointer to incomplete type.

Ошибка находится в строке 6, где я использовал неполный тип, как если бы это был полный тип. Я был в порядке до тех пор.

Ошибка в том, что вы должны были включить любой заголовок, определяющий тип. Но компилятор никак не может угадать, в какой строке это должно было быть включено: подойдет любая строка вне функции. Он также не будет просматривать каждый текстовый файл в вашей системе в поисках заголовка, который его определяет, и предлагать вам включить его.

В качестве альтернативы (хорошее замечание, картофельная мука) ошибка находится в строке, где было определено b, когда вы хотели указать какой-то тип, который действительно существует, но на самом деле указали blah. В большинстве случаев найти определение переменной b не должно быть слишком сложно. IDE обычно могут сделать это за вас, предупреждения компилятора, возможно, не беспокоят. Однако это довольно отвратительный код, если вы не можете найти определения вещей, которые вы используете.

person Community    schedule 23.04.2010

Я не совсем понимаю, в чем проблема. Неполный тип — это не тот тип, который «отсутствует». Неконкурентный тип — это тип, который объявлен, но не определен (в случае структурных типов). Найти не определяющее объявление легко. Что касается нахождения отсутствующего определения... здесь компилятор вам не поможет, так как именно это и вызвало ошибку в первую очередь.

Основной причиной неполных ошибок типов в C являются опечатки в именах типов, которые не позволяют компилятору сопоставить одно имя с другим (например, при сопоставлении объявления с определением). Но опять же, здесь компилятор вам не поможет. Компилятор не делает догадок об опечатках.

person AnT    schedule 23.04.2010

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

person catzilla_waw    schedule 09.01.2012
comment
Согласен. Сначала проверьте опечатки в определениях структур и объявлениях, а также в определениях типов. - person Daniel Farrell; 28.11.2017

Решение

Говоря о языке C, я только что эмпирически обнаружил, что решением будет следующий код объявления;

typedef struct ListNode
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;

Поэтому, как правило, я даю одно и то же имя как для определения типа, так и для имени структуры;

typedef struct X
{
    // code for additional types here
    X* prev; // reference to pointer
    X* next; // reference to pointer
} X;

B - Проблемные образцы

Если следующие объявления считаются неполными компилятором gcc при выполнении следующего оператора. ;

removed->next->prev = removed->prev;

И я получаю ту же ошибку для кода разыменования, указанного в выводе ошибки;

>gcc Main.c LinkedList.c -o Main.exe -w
LinkedList.c: In function 'removeFromList':
LinkedList.c:166:18: error: dereferencing pointer to incomplete type 'struct ListNode'
     removed->next->prev = removed->prev;

Для обоих объявлений файла заголовка, перечисленных ниже;

typedef struct
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;

Плюс этот;

typedef struct ListNodeType
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;
person Levent Divilioglu    schedule 12.02.2017

Вне возможных сценариев, связанных с оптимизацией всей программы, код кода, сгенерированный для чего-то вроде:

struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
  return blah ? whatever: bar;
}

совершенно не зависит от того, какие элементы struct foo могут содержаться. Поскольку утилиты make обычно перекомпилируют любую единицу компиляции, в которой появляется полное определение структуры, даже если такие изменения фактически не могут повлиять на сгенерированный для них код, принято опускать полные определения структур из единиц компиляции, которые на самом деле не нужны. их, и такое упущение, как правило, не заслуживает предупреждения.

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

Между прочим, есть еще одна ситуация, когда Стандарт позволяет компилятору требовать, чтобы полное определение объединения было видимым, но не требует диагностики: если две структуры начинаются с Общей начальной последовательности, а тип объединения, содержащий оба, виден, когда компилятор является обрабатывающим кодом, который использует указатель одного из типов структур для проверки члена этой общей начальной последовательности, компилятор должен распознать, что такой код может обращаться к соответствующему члену структуры другого типа. Я не знаю, какие компиляторы, если таковые имеются, соответствуют стандарту, когда виден полный тип объединения, но не когда он не виден [gcc склонен генерировать несоответствующий код в любом случае, если только не используется флаг -fno-strict-aliasing, и в этом случае он будет генерировать соответствующий код в обоих случаях], но если кто-то хочет написать код, который использует правило CIS таким образом, чтобы гарантировать правильное поведение на соответствующих компиляторах, может потребоваться убедиться, что полное определение типа объединения видно; невыполнение этого требования может привести к тому, что компилятор молча сгенерирует фиктивный код.

person supercat    schedule 13.02.2017