Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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

typedef struct a {
    ...
} a;

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

A - Решение

Говоря о языке 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;

Ответ 7

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

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

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

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

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