Как проверить, можно ли безопасно привести указатель void * к чему-то другому? - PullRequest
4 голосов
/ 01 февраля 2012

Допустим, у меня есть эта функция, которая является частью некоторого набора инструментов GUI:

typedef struct _My_Struct My_Struct;
/* struct ... */

void paint_handler( void* data )
{
   if ( IS_MY_STRUCT(data) ) /* <-- can I do something like this? */
   {
      My_Struct* str = (My_Struct*) data;
   }
}

/* in main() */
My_Struct s;
signal_connect( SIGNAL_PAINT, &paint_handler, (void*) &s ); /* sent s as a void* */

Поскольку paint_handler также будет вызываться основным циклом инструментария GUI с другими аргументами, я не всегда могу быть уверен, что параметр, который я получаю, всегда будет указателем на s.

Могу ли я сделать что-то вроде IS_MY_STRUCT в функции paint_handler, чтобы проверить, что полученный параметр можно безопасно вернуть обратно к My_Struct*?

Ответы [ 6 ]

18 голосов
/ 01 февраля 2012

Ваш указатель void теряет всю информацию о своем типе, поэтому одним только этим вы не сможете проверить, может ли он быть безопасно приведен.Программист должен знать, может ли void* быть безопасно приведен к типу.

3 голосов
/ 01 февраля 2012

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

3 голосов
/ 01 февраля 2012

К сожалению, нет функции для проверки того, каким был указатель, прежде чем он появится в этом контексте (void).

Единственное решение, которое я могу придумать, - это если вы поместите int _struct_id в качестве первого члена всех ваших структур.Этот член id может быть безопасно проверен независимо от типа, но это не удастся, если вы передадите указатели, которые не реализуют этот член (или int, char, ... pointers).

0 голосов
/ 12 мая 2015

Я знаю, что вопросу 3 года, но я иду, Как насчет использования простого глобального перечисления, чтобы отличить, откуда вызывается функция. тогда вы можете переключаться между типами, к которым нужно привести указатель void.

0 голосов
/ 24 октября 2012

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

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

Пример:

typedef struct {
    ULONG  ulSignature1;
    //  .. data elements that you want to have
    ULONG  ulSignature2;
} MySignedStruct;
#define MYSIGNEDSTRUCT_01  0x1F2E3D4C
#define MYSIGNEDSTRUCT_02  0xF1E2D3C4

#define IS_MY_STRUCT(sAdr)  ( (((MySignedStruct *)sAdr)->ulSignature1 == MYSIGNEDSTRUCT_01  ) && (((MySignedStruct *)sAdr)->ulSignature1 == MYSIGNEDSTRUCT_02))

Это грубый подход, однако он может помочь.Естественно, использование макроса типа IS_MY_STRUCT(), где аргумент используется дважды, может быть проблематичным, если аргумент имеет побочный эффект, поэтому вам следует быть осторожным с чем-то вроде IS_MY_STRUCT(xStruct++), где xStruct - указатель на MySignedStruct.

0 голосов
/ 01 февраля 2012

Там действительно нет в с.void указатели не имеют типов и должны использоваться только тогда, когда вы действительно знаете, на что они указывают.

Возможно, вам следует вместо этого пересмотреть свой дизайн;переписать свой код, так что проверка не требуется.По этой же причине Google запрещает RTTI в своем руководстве по стилю .

...