2012-06-05 3 views
4

Предположим, у меня есть следующие структур:Можно ли проверить, имеет ли переменная тип struct?

struct A{ 
    int a; 
} a; 

struct B{ 
    A a; 
    int b; 
} b; 

как проверить, если b имеет тип B или если b имеет тип A?

+1

Просто посмотрите декларацию? –

+0

Вы имеете в виду программную проверку во время выполнения? – Joe

+1

Нет типа 'B' или типа' A'. Существует тип 'struct B', и вот что такое b. –

ответ

11

Вы имеете в виду во время выполнения, учитывая void *, который указывает на то, что один или другой? К сожалению, это невозможно; C не имеет какого-либо механизма информации о времени выполнения.

+0

Поэтому я должен указать поле «тип» с некоторым значением и проверить это значение, чтобы найти «тип»? :( – Fabricio

+0

@Fabricio: Обычный способ заключается в использовании некоторых вариантов 'struct {int type; union {type1 t1; type2 t2} data}' –

+2

@Fabricio - см. Мой ответ для примера. – Unsigned

0

Что касается C, данные - это всего лишь строка бит. Как вы используете и интерпретируете данные, зависит от программиста.

Это точно так же, как char может представлять символ, положительное число или отрицательное число (или что-то еще в этом случае). Это зависит от контекста и того, как он используется программистом.

-2

Вы можете его взломать? Если это действительно необходимо, и у вас есть пара структур.

struct A{ 
    int a; 
    int identifer = 0; 
} a; 

struct B{ 
    A a; 
    int b; 
    int identifer = 1; 
} b; 

И если ваш код может быть как

if object->identifer == 0 
    bla bla bla 
+0

Это не может работать. –

+0

возможность доступа к 'object-> identifier' означает, что вы знаете о его типе уже –

+0

@DanF нет, если у вас есть это в обеих (все) структурах. Снова его взломать. Единственное, о чем я не уверен, - это установить те значения по умолчанию ... –

0

No. В отличие от C++, который использует vtable для поддержания ассоциаций типа во время выполнения, C не предоставляет метод для выполнения проверки типа.

Возможный обходной путь будет присвоить тип идентификторов в качестве первого элемента структуры:

struct A { 
    int type; 
    int a; 
} a; a.type = 'A'; 

struct B { 
    int type; 
    A a; 
    int b; 
} b; b.type = 'B'; 

// Now, given a (void*) pointer `ptr`, of either `A` or `B`... 
if (*(int*)ptr == 'A') 
{ 
    // ... 
} 
elseif (*(int*)ptr == 'B') 
{ 
    // ... 
} 
+0

Это не может работать, если у вас есть только указатель на объект. –

+0

Доступ к члену 'type' означает, что вы уже знаете что-то о типе объекта. –

+1

@DanF. Напротив, это возможно иметь указатель (void *) и ничего не знать о типе объекта. См. Комментарий, приведенный в моем примере. – Unsigned

2

во время компиляции:

#define WARN_IF_DIFFERENT_STRUCT_TYPE_1(T, o) do { \ 
    T temp = (o);         \ 
    (void) temp;         \ 
} while (0) 

пример:

struct B b; 
/* will warn if b is not of struct A type */ 
WARN_IF_DIFFERENT_STRUCT_TYPE_1(struct A, b); 

С два объекта передаются в качестве макропараметров с использованием typeof Расширение GNU:

#define WARN_IF_DIFFERENT_STRUCT_TYPE_2(o1, o2) do { \ 
    typeof(o1) temp = (o2);       \ 
    (void) temp;          \ 
} while (0) 

пример:

struct A a; 
struct B b; 
/* will warn if a and b are not the same struct type */ 
WARN_IF_DIFFERENT_STRUCT_TYPE_2(a, b);   
+1

Вам не нужно расширение gnu: 'typedef char dummy [sizeof (1? A: B)]' будет делать, чтобы определить, совместимы ли типы 'A' и' B' (после возможного преобразования в rvalue). –

+0

@JensGustedt да, хороший, я не думал об условном операторе – ouah

0

Если вы собираетесь написать свой собственный механизм проверки типа я рекомендую писать макросы для заполнения поля для вас.

typedef struct A { 
    void *type; 
    int a; 
} A; 

Этот макрос инициализирует каждую структуру с его тип информации с помощью stringification:.

#define InitializeType(ptr, type) \ 
     ((ptr)->type == (void *)(#type ## __FILE__ ##)) 
#define IsType(ptr, type)  \ 
     ((ptr)!=NULL && (ptr)->type != (void *)(#type ## __FILE__ ##)) 

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

A alpha; 
InitializeType(&alpha, A); 
IsType(&alpha, A); 

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

Смежные вопросы