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


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

7 54

7 ответов:

Я видел вопрос на днях, где кто-то случайно использовал неполный тип, указав что-то вроде struct a { int q; }; struct A *x; x->q = 3;. Компилятор знал, что struct A была структура, несмотря на A быть полностью неопределенным, в силу struct ключевое слово.

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

typedef struct a {
    ...
} a;

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

Что значит, ошибка появляется только при назначении? Например, на 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 обычно могут сделать это за вас, предупреждения компилятора, возможно, не могут быть обеспокоены. Это довольно отвратительный код, хотя, если вы не можете найти определения вещей, которые вы используете.

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

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

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

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

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

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;

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

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

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

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

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