Как вы проверяете, имеет ли указатель в C определенный тип?

Как вы проверяете, имеет ли указатель определенный тип?

Использование sizeof недостаточно.

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

Ответ 1

Gcc не ставит определение структуры нигде во время выполнения. Это означает, что вы не можете стандартно.

Это зависит от того, для чего вы используете информацию типа. Два основных приложения могут быть:

  • Отладка или аналогичная проверка времени выполнения
  • Сериализация и десериализация структур данных

В первом случае информация часто доступна в символах, выводимых компилятором и прикрепленных к исполняемому файлу (во многих средах).

Реализация является специфичной для платформы и часто означает, что компилятор должен быть проинструктирован для вывода этой информации. Одним из примеров этой программы является gdb. Указатели по-прежнему должны быть введены правильно, чтобы это было полезно.

Для типов сериализации часто помечены значения, как вы предлагаете. Эти теги не должны храниться с данными в памяти. Они могут быть добавлены программой вывода.

Ответ 2

Вы не можете.

Указатель просто хранит адрес и ничего не связан с содержимым этого адреса.

Ответ 3

"Я пытаюсь не вводить idnumbers в свои структуры, чтобы идентифицировать их тип". Не избегайте этого. Если вы действительно хотите проверить тип, поместите идентификатор типаID в качестве первого элемента каждой структуры. Ваш импульс не был плохим.

Ответ 4

Указатель - это тип. В более общем плане, C не дает возможности делать интроспекцию. Нет никакого программного способа определить тип переменной.

Ответ 5

Все ответы, размещенные здесь, говорят "вы не можете". Они правы. Вы не можете.

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

Какая игра? Набивание лишних битов данных в неиспользуемые части адреса и удаление их, где бы вы не использовали адрес.

Итак, представьте, что у вас есть указатели на структуру или класс размером 32 байта. Если вы убедитесь, что выделение памяти выровнено по 32-байтовому адресу (что легко для динамических распределений, но сложнее гарантировать наличие стека), младшие биты адреса будут равны 0. Это означает, что 5 свободных бит в в нижней части адреса, достаточно для размещения флагов, идентификационных номеров, значений состояния и т.д. Хранилище бесплатное! Даже если у вас размер нечетной структуры, практически любой компилятор и ОС C или С++ всегда выравнивают каждый адрес до 4 байтов.

В 64 битах вы обычно можете найти значительное количество бесплатных битов в верхнем конце адресов... очень вероятно, что 16 бесплатных неиспользуемых битов ждут вас. Конечно, это зависит от ОС. А также плохую плохую идею рассмотреть. Вам нравится опасность, не так ли?

Двумя минутами являются:

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

Ваша судьба, если вы последуете моему совету http://ecoworldly.com/files/2008/11/siberian-tiger-amur-tiger-korean-tiger.jpg

Там так много способов, что это взорвется на ошибки, сбои и боль. Помните, как я сказал, что компиляторы выравнивают память как минимум на 4 байта? Ну, это правда. Пока вы не найдете новую ОС, которая этого не сделает. И ты пища тигра.

Так что не делай этого.

Но, тем не менее, это действительно способ набить немного дополнительной информации, такой как номер типа, на каждый адрес. Вы можете увидеть эту технику в код каждого байта или Obfusicited C.

PS: Действительно, я имею в виду это, не делай этого. Даже если вам нравятся тигры.

Ответ 6

Нет, нет информации о времени выполнения в любом месте.

Вы должны написать свои функции, чтобы подпись функции содержала информацию о типе и позволяла компилятору проверять типы статически. Например, void burp_foo(struct foo *thefoo) указывает, что аргумент является указателем на struct foo. Это нужно, чтобы вызывающий абонент мог его предоставить. Разумеется, благодаря типу casting можно указать любой указатель, указывающий на struct foo, но затем это проблема вызывающего абонента, а не ваша.

Ответ 7

Вы не можете сделать это в C. Фактически компилятор С++ делает что-то вроде того, что вы хотите (сохраняя информацию о типе класса в выделенной памяти). В C у вас нет классов, а только структур, которые не содержат никаких накладных расходов.

Ответ 8

Способ избежать ввода идентификатора в вашей структуре - использовать полиморфизм, например:

typedef struct {
        char const *name;
        int id;
        /* ... */
} object_info_t;

typedef struct {
        object_info_t *info;
} object_t;

typedef struct {
        object_t object;
        int a;
} foo_t;

typedef struct {
        object_t object;
        int b;
} bar_t;

int object_get_id(object_t *object)
{
        return object->info->id;
}

Обратите внимание, что вы можете добавить object_info_t указателями на функции и вообще не проверять id:

typedef struct {
        char const *name;
        int id;
        int (*do_something)(object_t *);
} object_info_t;

int object_do_something(object_t *self)
{
        return self->info->do_something(self);
}

Ответ 9

В C. В этом нет ничего подобного. Указатель имеет либо определенный тип, либо void*. Там нет функции перегрузки или встроенного полиморфизма времени выполнения, как на С++. Вы можете, хотя и использовать псевдо-объектно-ориентированные трюки, используя указатели функций, например:


typedef void (*cmd_func)( int );
struct command
{
    int      arg;
    cmd_func action;
};

Ответ 10

Стандарт C не позволяет это напрямую. Стандарт С++ имеет некоторую возможность сделать это (dynamic_cast и typeid).

typeof

GCC поставляется с оператором typeof, который может быть полезен в зависимости от того, что вы делаете.

условный оператор

Условный оператор (знак вопроса и двоеточие в выражениях типа x = y == 0 ? 1 : 0;) имеет некоторую способность сказать вам, можно ли принудить два типа к третьему type (эта статья посвящена С++, но безопасность типа условного оператора в C). Его использование, по меньшей мере, неочевидно.

Оба этих метода (typeof и условный оператор) ограничены тем, какая информация доступна во время компиляции. То есть вы не можете передать void* функции, а затем использовать typeof для определения исходного типа объекта, на который указывает указатель внутри этой функции (поскольку такая информация недоступна внутри этой функции при компиляции время).


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

Ответ 11

Ну, один из возможных способов - сохранить адрес указателя и увеличить указатель, чтобы увидеть его новый адрес. Разница даст подсказку.