2015-08-25 2 views
2

Я был на классах Data Structures, и это меня смутило.C: аномалия структуры и указателей Typedef

Это связано с свойствами указателей, я думаю, но по моему исследованию я не нашел никакого реального объяснения, любой идеи, почему C позволяет это?

Run-код, который может: http://ideone.com/kgh3LF

#include <stdio.h> 
#include <stdlib.h> 

/* Declaring a typedef struct */ 
typedef struct{ 
    int a; 
    char b[10]; 
}struct_one; 

/* Declaring another structure, with an intentional wrong calling of the first structure */ 
struct struct_two{ 
    int p; 
    char q[10]; 

    /* This doesn't work as expected... should be: struct_one var; */ 
    // struct struct_one var; 

    /* THIS ONE DOES WORK!!, and i'm not sure why */ 
    struct struct_one *ptr; 
}; 

int main(void) { 
    /* code */ 
    return 0; 
} 
+3

Вы неявным образом объявляете тип 'struct struct_one' при объявлении указателя на тот же. Если вы хотите увидеть, как это происходит, попробуйте 'struct two obj; obj.ptr = malloc (sizeof * obj.ptr); 'в' main() ', тем самым выдавая [существенное сомнение] (http://ideone.com/4fcdXF) на« этот работает! ». – WhozCraig

+2

Вот почему я не согласен с «общей» (?) Мудростью, чтобы не печатать ваши структуры. Опечатка в имени typedef попадает в компилятор, но опечатка в теге struct может отсутствовать, в зависимости от того, как она используется. –

ответ

3

Вы ошибочно предположили, что ваша вторая структура «вызывает» первую. Это не так.

В действительности первая декларация структуры объявляется как untagged тип структуры с псевдонимом typedef struct_one. Единственный способ обратиться к этому типу - struct_one. Только struct_one, а не struct struct_one.

Вторая декларация структуры объявляет struct struct_two, что относится к типу struct struct_one. Этот последний тип не имеет абсолютно никакого отношения к ранее объявленному типу struct_one: struct struct_one и struct_one - это два совершенно разных, несвязанных типа. Ваша ссылка на struct struct_one внутри второй структуры рассматривается как введение, a декларация совершенно нового типа struct struct_one. Компилятор предполагает, что вы позже определите этот тип (при необходимости).

Поскольку вы ничего не делаете в своем коде, вы не сталкиваетесь с какими-либо проблемами, вызванными такой ошибкой. В качестве дополнительной иллюстрации того, что может произойти, следующий пример

int main(void) { 
    struct_one *p = 0; 
    struct struct_two s2; 
    s2.ptr = p;  
    return 0; 
} 

Этот код будет немедленно произвести диагностическое сообщение от компилятора, поскольку s2.ptr = p; присвоение является незаконным: типы указателей не имеют никакого отношения. Указатель левой стороны - struct struct_one *, а указатель справа - struct_one *.

Еще раз, в языке C при использовании struct <something> синтаксиса в контекстах, которые не требуют полного типа, вы можете написать практически все, что вместо <something>: полного бреда (до тех пор, как это лексический действительный идентификатор). Если тип еще не известен, компилятор просто предположит, что вы вводите новый тип, например.

int main() { 
    struct klshcjkzdcdsamcbsj78q43698 *p = 0; 
} 

Вышеупомянутая версия является полностью действующей программой C.

0

Это допускается, потому что иногда у вас есть два типа структуры, которые каждый из которых содержит указатель на другой. Вы должны иметь возможность объявить указатель на второй тип в первом, хотя вторая структура еще не объявлена. Если вы не можете перенаправить ссылку на тип указателя struct, у вас будет парадокс, что каждый должен быть объявлен перед другим.

struct first { 
    int a; 
    struct second *second_ptr; // This is allowed 
}; 
struct second { 
    int b; 
    struct first *first_ptr; 
} 
Смежные вопросы