Предположим, у меня есть следующие структур:Можно ли проверить, имеет ли переменная тип struct?
struct A{
int a;
} a;
struct B{
A a;
int b;
} b;
как проверить, если b
имеет тип B
или если b
имеет тип A
?
Предположим, у меня есть следующие структур:Можно ли проверить, имеет ли переменная тип struct?
struct A{
int a;
} a;
struct B{
A a;
int b;
} b;
как проверить, если b
имеет тип B
или если b
имеет тип A
?
Вы имеете в виду во время выполнения, учитывая void *
, который указывает на то, что один или другой? К сожалению, это невозможно; C не имеет какого-либо механизма информации о времени выполнения.
Поэтому я должен указать поле «тип» с некоторым значением и проверить это значение, чтобы найти «тип»? :( – Fabricio
@Fabricio: Обычный способ заключается в использовании некоторых вариантов 'struct {int type; union {type1 t1; type2 t2} data}' –
@Fabricio - см. Мой ответ для примера. – Unsigned
Что касается C, данные - это всего лишь строка бит. Как вы используете и интерпретируете данные, зависит от программиста.
Это точно так же, как char
может представлять символ, положительное число или отрицательное число (или что-то еще в этом случае). Это зависит от контекста и того, как он используется программистом.
Вы можете его взломать? Если это действительно необходимо, и у вас есть пара структур.
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
Это не может работать. –
возможность доступа к 'object-> identifier' означает, что вы знаете о его типе уже –
@DanF нет, если у вас есть это в обеих (все) структурах. Снова его взломать. Единственное, о чем я не уверен, - это установить те значения по умолчанию ... –
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')
{
// ...
}
Это не может работать, если у вас есть только указатель на объект. –
Доступ к члену 'type' означает, что вы уже знаете что-то о типе объекта. –
@DanF. Напротив, это возможно иметь указатель (void *) и ничего не знать о типе объекта. См. Комментарий, приведенный в моем примере. – Unsigned
во время компиляции:
#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);
Вам не нужно расширение gnu: 'typedef char dummy [sizeof (1? A: B)]' будет делать, чтобы определить, совместимы ли типы 'A' и' B' (после возможного преобразования в rvalue). –
@JensGustedt да, хороший, я не думал об условном операторе – ouah
Если вы собираетесь написать свой собственный механизм проверки типа я рекомендую писать макросы для заполнения поля для вас.
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 * как первый параметр в каждая структура.
Просто посмотрите декларацию? –
Вы имеете в виду программную проверку во время выполнения? – Joe
Нет типа 'B' или типа' A'. Существует тип 'struct B', и вот что такое b. –