2016-07-07 1 views
-3

Я хочу наложить указатель на одну из двух структур в зависимости от значения переменной. Я пробовал это, но он не работает -C - Визуальный указатель на void для динамической структуры

struct typeA 
{ 
    int a; 
    int x; 
} 
struct typeB 
{ 
    int b; 
    int a; 
    int x; 
    int z; 
} 


int band=1; 
void *ptr; 

if(band == 1) 
      ptr = (struct typeA *)malloc(sizeof(struct typeA)); 
else if(band == 2) 
      ptr = (struct typeB *)malloc(sizeof(struct typeB)); 

printf("A:%d",ptr->a);//error: structure type required instead of void 

Какой был бы лучший способ сделать это?

EDIT: Добавлены определения структуры и ошибки (в комментариях кодов), чтобы иметь больше смысла.

+2

В C не нужно вносить листинг. (Также 'ptr'' 'void *') Пожалуйста, объясните, что «не работает». – BLUEPIXY

+1

Я проигнорировал, потому что вы говорите, что ваш код не работает, но вы не говорите, почему, какая ошибка или предупреждение, которое дает вам компилятор. Измените свой вопрос, предоставив эту информацию, и я удалю свой downvote. – nbro

+0

Остановить кастинг 'malloc()', но дать реальный тип 'ptr'. Если на самом деле есть веская причина, чтобы 'ptr' был' void * ', то почему бы просто не выделить более крупные из двух размеров? И, хм, * «это не работает» * - ужасное описание вашей проблемы. Включите сообщение об ошибке! – DigitalRoss

ответ

1

Если вам не нужно знать, какой тип структуры вы должны использовать

if(band == 1) 
     ptr = malloc(sizeof(struct typeA)); 
else if(band == 2) 
     ptr = malloc(sizeof(struct typeB)); 

Возвращаемый тип malloc уже void *.

Однако, это code smell --- вам действительно не нужно знать размер или тип структуры после ее создания? Я бы немного пересмотрел ваш дизайн.

Редактировать Основываясь на дополнительном коде, опубликованном вами, я настоятельно рекомендую новый подход. Например, поля в typeA и typeB находятся в другом порядке, поэтому нет никакого способа для ptr->a ссылаться на оба из них, независимо от типа ptr. Если вы застряли в простой C, рассмотрите один struct, который имеет a и x и необязательный указатель на отдельную структуру с b и z. Или всего, для этого используйте только typeB, и уберите typeA!

1

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

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

EDIT:

Ошибка в том, что вы пытаетесь разыменовывать void *, что является незаконным.

Вместо одной переменной используйте два (один из каждого типа), а другой - NULL. Альтернативно, если вы знаете тип данных, на который указывает void *, вы можете перевести его в соответствующий тип, а затем разыщите его.

+0

Типы не совпадают, но 'void *' является наиболее общим типом указателя, поэтому не должно быть проблем с назначением указатель на любой другой тип на 'void *', или я ошибаюсь? Не ливень. – nbro

1

Броски здесь ничего не покупают, потому что результат каждого литья сразу преобразуется в тип ptr. В любом случае указатель на объект malloc заканчивается сохраненным в ptr, а ptr имеет ровно один статический тип, который точно соответствует возвращаемому malloc. Единственным поведением, которое отличается, является размер области malloc.

Ваша логика может быть сведена к однострочнику:

void *ptr = malloc(band == 1 ? sizeof (struct typeA) : sizeof (struct typeB)); 

Намного больше контекста требуется, чтобы увидеть, будет ли это хороший подход в отношении к окружающему коду, или что-то более дисциплинированный «ООП «похоже» было бы лучше, или простой переход между двумя отдельными фрагментами кода, работающими на отдельных структурах.

Реальный объект не может быть доступен как typeA или typeB без дополнительных слепков, так что можно себе представить, что много некрасивого код следующим образом, например,

if (band == 1) 
    do_this_A_version((struct typeA *) ptr)->foo, x); 
else 
    do_this_B_version((struct typeB *) ptr)->bar, y); 

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

1

[EDIT] Фрагмент кода, обновленный после редактирования OP.

Это вопрос догадки Актуальность вопроса, но, возможно, следующее, что вы после.

struct typeA 
{ 
    int a; 
    int x; 
}; 
struct typeB 
{ 
    int b; 
    int a; 
    int x; 
    int z; 
}; 

union { struct typeA *A; struct typeB *B; } ptr; 
if(band == 1) 
    ptr.A = malloc(sizeof(struct typeA)); 
else if(band == 2) 
    ptr.B = malloc(sizeof(struct typeB)); 

/* ... later on ... */ 

if(band == 1) 
    printf("A::a = %d", ptr.A->a); /* use ptr.A as a struct typeA pointer */ 
else if(band == 2) 
    printf("B::a = %d", ptr.B->a); /* use ptr.B as a struct typeB pointer */ 
2

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

Однако для устранения ошибки компиляции вы получаете вы можете сделать что-то вроде этого:

printf("A:%d",(band == 1) ? ((struct typeA *)ptr)->a : ((struct typeB *)ptr)->a); 

Вы получаете сообщение об ошибке, потому что вы пытаетесь получить доступ к члену a из void * когда вы делаете (ptr->a).

Вам необходимо направить его, чтобы сказать, что ptr указывает на struct typeA или struct typeB.