Портативный способ «отменить» указатель typedef? - PullRequest
3 голосов
/ 09 ноября 2010

К сожалению, это определено в некоторой внешней библиотеке: не может коснуться!

// library.h
typedef struct {
    long foo;
    char *bar;
   /* ... (long & complex stuff omitted) */
} *pointer_to_complex_struct_t;

Сейчас Вопрос : как объявить переменную complex_struct_t?

  • Идеальное решение, но не допускается!(невозможно изменить внешнюю библиотеку):

    // library.h
      /* ... (long & complex stuff omitted) */
    } complex_struct_t, *pointer_to_complex_struct_t;
    
    
    // my.h
    extern complex_struct_t my_variable;
    
  • Непереносимое решение (gcc):

    // my.h
    extern typeof( * (type_placeholder)0 )  my_variable; // Thanks caf!
    
  • Другое?Лучше?Спасибо!

Бонусный вопрос: тот же вопрос для указателя функции (если есть какая-либо разница; я сомневаюсь в этом).


ДОБАВЛЕННЫЙ бонус: нижеточно такой же вопрос, но с функциями вместо структур.Это не должно иметь никакого значения для короткого ответа («Нет»), единственного ответа, который меня первоначально интересовал. Я не ожидал, что некоторые люди умрут, пытаясь узнать и выполнить мою работу с помощью творческих обходных путей, поэтому яУпростил вопрос от функций к структурам (для удобства указатели имеют специальные неявные правила преобразования для удобства и путаница).Но почему бы и нет?Давайте начнем конкурс обхода копирования и вставки.Некоторые обходные пути, вероятно, лучше других.

///// library.h //////
// Signature has been simplified
typedef double (*ptr_to_callback_t)(long, int, char *);
// Too bad this is not provided: typedef double callback_t(long, int, char *);

///// my.h /////
// This avoids copy-paste but is not portable
typedef typeof( * (ptr_to_callback_t)0 ) callback_t;

extern callback_t callback_1;
extern callback_t callback_2;
extern callback_t callback_3;
// etc.

Краткий ответ = нет, в настоящее время нет портативной альтернативы typeof

Базовый обходной путь копирования-вставки работает нормально для функции , но не для структур .Компилятор будет соответствовать дублированным типам функций , но не будет связывать дублированные типы структур : приведение требуется, и дублированные типы структур будут расходиться без предупреждения компиляции.

Ответы [ 4 ]

2 голосов
/ 09 ноября 2010

Нет, к сожалению, вы не можете сделать это со стандартным C. С C ++ простая метафункция сделала бы все же.

Однако вы можете просто скопировать и вставить определение структуры, оставив оригинал нетронутым

typedef struct {
 ///same  struct
} complex_struct_t;

Недостатком этого решения является то, что выражение &complex_struct_t не будет иметь тип pointer_to_complex_struct_t, вместо этого оно будет иметь указатель типа на безымянный struct {//your members}; Вам понадобится reinterpret_casting, если вам нужна эта функция ...

1 голос
/ 09 ноября 2010

Как написано, ответ на ваш вопрос "нет";если все, что у вас есть, это определение типа

typedef struct {...} *ptr_to_struct;

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

ptr_to_struct s = malloc(sizeof *s);

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

Вы спросили, применяется ли то же самое к указателям на функции;вам действительно нужно точно указать, что вы имеете в виду.Если у вас есть ситуация, подобная

typedef struct {...} *ptr_to_struct;
ptr_to_struct foo() {...}

, то ситуация точно такая же, как указано выше;у вас нет способа объявить переменную этого типа.

0 голосов
/ 09 ноября 2010

Как насчет:

pointer_to_complex_struct_t newStruct ( void ) {
    pointer_to_complex_struct_t ptr = 
         (pointer_to_complex_struct_t) malloc ( sizeof (*pointer_to_complex_struct_t) );
    return ptr;
}

Вы должны ссылаться на свою вновь созданную структуру через ptr->, но вы можете создавать новые.

Конечно, это может или не можетработать, в зависимости от того, как структура на самом деле используется.Пример, который приходит на ум: что если структура заканчивается на

char data[0];

и данные используются для указания на память, следующую за структурой.

0 голосов
/ 09 ноября 2010

Сделайте локальную копию файла заголовка и включите его вместо оригинала. Теперь вы можете делать все, что захотите. Если эта библиотека может измениться (обновить или что-нибудь еще), вы можете написать небольшой скрипт для автоматизации этих шагов и вызывать его из вашего make-файла всякий раз, когда вы компилируете. Просто убедитесь, что не вставляете вслепую в заголовок, найдите конкретную строку (} *pointer_to_complex_struct_t;) и выдавайте ошибку, если она больше не найдена.

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

РЕДАКТИРОВАТЬ (для вашей реальной цели, упомянутой в комментарии): Вы не можете сделать это с помощью указателей на функции. Просто напишите нужную функцию с подписью typedef, и она будет совместима с указателем и может вызываться им.

...