2016-03-31 4 views
2

Моя программа содержит несколько структур, которые имеют только один общий параметр. Пример:Есть ли способ узнать, какой тип структуры указывает указатель?

struct first { 
    var a; 
    var b; 
    var common_var; 
    var c; 
}; 

struct second { 
    var d; 
    var common_var; 
    var e; 
    var f; 
}; 

«common_var» является параметром, который все имеют в Структуры общего, но он не появляется в том же порядке для различных структур. В первой-структуре это третья переменная, а во второй-структуре это вторая переменная.

Теперь у меня есть функция, которая принимает указатель-на-void как аргумент. Я хочу передать указатели на любую из этих структур, на эту функцию и сделать материал на основе «common_var» -переменной.

void main() 
{ 
    struct first * pFirst; 
    theFunctionIMentioned(pFirst); 
} 

void theFunctionIMentioned(void * p) 
{ 
    /* Get hold of "common_var" parameter somehow. */ 
    /* Do something based on the "common_var" parameter. */ 
} 

Если «common_var» была первой записью во всех структурах, это не было бы проблемой. Однако я действительно хочу избежать этого.

Итак, вопрос: могу ли я как-нибудь выяснить, является ли аргумент функции (void * p) указателем на первую-структуру или указателем на вторую-структуру?

EDIT 1: Проблема заключается в том, что эта программа имеет интерфейс, который позволяет (косвенно, конечно) для пользователя, чтобы «решить», что структура указатель передается в функцию. Если пользователь выполняет действие A, то программа передает указатель на первый в функцию. Если пользователь выполняет действие B, он передает указатель на секунду функции. Однако программа не может (ни при каких обстоятельствах) знать, было ли выполнено действие A или действие B пользователем. Таким образом, в основном, единственное, что я «знаю» во время программирования, это то, что аргумент, переданный в «theFunctionIMentioned()», является указателем на структуру, содержащую «common_var». Я привык программировать объектно-ориентированный, и в этом случае я бы решил это, используя какой-то интерфейс-механизм. Наверное, я надеюсь, что будет такая же кодовая техника в C.

ответ

1

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

Я предлагаю вам принять общий параметр common_var в качестве параметра функции и использовать его таким образом.

void theFunctionIMentioned(var common_var) 

void main() 
{ 
    struct first * pFirst; 
    theFunctionIMentioned(pFirst->common_var); 
} 
+0

Спасибо за ответ! Проблема в том, что во время программирования я не знаю, какой указатель передан. – pose

1

В именах переменных C присутствуют только во время этапа компиляции и ссылки, но во время выполнения они недоступны. Вы должны подумать о другом решении, с помощью которого вы можете получить доступ к значению. Один из таких случаев могут быть

void main() 
{ 
    struct first * pFirst; 
    theFunctionIMentioned(pFirst, pFirst->common); 
} 

void theFunctionIMentioned(void * p, var common) 
{ 
    /* Get hold of "common_var" parameter somehow. */ 
    /* Do something based on the "common_var" parameter. */ 
} 
+0

Спасибо за ваш ответ! Прошу прощения за то, что я не был достаточно конкретным в моем вопросе. Проблема в том, что во время программирования у меня нет способа узнать, принимает ли «theFunctionIMentioned» указатель на первый или указатель на второй. – pose

0

Структура first и second отличается тип структур, определенным вами. Вы не можете изменить один на другой. Когда вы объявляете указатель на один из них, вы можете передать его theFunctionIMentioned. Но вы будете знать его тип, как вы его объявите.

Кроме того, проходит ли указатель на структуру first или на структуру second, вы можете получить доступ к любому из переменных с помощью pFirst->variable; где pFirst является указателем вы объявляли и variable переменных вы хотите.

+0

Спасибо за ответ! Я уточнил свой вопрос, чтобы быть более конкретным. В фактическом коде строка кода «theFunctionIMentioned (pFirst)» никогда не появится, потому что я не знаю, какой указатель передан функции. Это будет больше похоже на «theFunctionIMentioned (somePointer)». Однако я знаю, что указатель относится к структуре, в которой снова содержится переменная «common_var». – pose

+0

@pose Почему бы вам просто не получить доступ к нему с помощью 'somePointer-> common_var;'? Позиция общей переменной в структуре не имеет значения. – Marievi

+0

Это потому, что мне нужно сначала нарисовать «somePointer» указателю на одну из этих структур. somePointer вводит программы как (void *), и я должен передать его либо (struct first *), либо (struct second *). Если я, следовательно, передам его (struct first *), то somePointer-> common_var получит доступ к неправильному адресу памяти, если somePointer фактически является (struct second *). – pose

2

Нет, указатель, когда программа запускается, является просто адресом памяти, а указательная память - это просто биты. Нет тегов скрытого типа.

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

Можете ли вы изменить структуры или исправить их ? Если вы можете их изменить, вы можете создать новую структуру с полем типа и союзом, состоящим из двух структур. Или вы можете вставить поле типа в начале обеих структур.

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

+0

Спасибо за ваш ответ! – pose

+0

Указатель может быть только адресом, но компилятор, который знает, что что-то было написано с помощью указателя какого-либо типа, а затем прочитал его как этот тип, может считать, что чтение будет давать прочитанное значение, даже если это хранилище было написано с помощью указателя другой тип - даже если оба типа имеют общую начальную последовательность, и указатели использовались для доступа к членам этой последовательности.Чистый эффект заключается в том, что тип указателя не сохраняется в ОЗУ, но компилятор может отслеживать его в любом случае для целей оптимизации. – supercat

1

Вопрос: Можно ли каким-либо образом выяснить, является ли аргумент функции (void * p) указателем на первую-структуру или указателем на вторую структуру?

Нет, как правило, такого метода нет. Информация о типе теряется при преобразовании в void*.

Похоже, что пользовательский интерфейс должен быть переписан. Чтобы иметь функцию с void*, которая принимает несколько разных структур, уже предлагает ошибочный дизайн программы - для разных случаев должны быть разные функции. (Указатели функций могут использоваться для создания согласованного интерфейса.)

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

+0

Хорошо, спасибо! Я подозревал столько же, но это стоило того выстрела. – pose

-1

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

пустота основной() {

struct first * pFirst; 
theFunctionIMentioned(pFirst, 1); 

}

void theFunctionIMentioned(void * p, var decider) // decider = 1 for first 
                //   = 2 for second 
                //   = 3 for third 
{ 
     if (decider == 1) 
     { 
      struct first * pFirst = (struct first*) p; 
     } 

    else 
    { 
     } 
}