2016-03-09 4 views
0

У меня есть метод в C, который ожидает двойной указатель в качестве аргумента:Должен ли я избегать ввода указателя?

void method(
    // in/out 
    double *dOne, 
    ...) 

Вызывающий имеет указатель поплавка

float *fOne; 

Что такое хороший способ вызова method() с fOne?

method((double*)fOne, ...); 

не самый лучший, не так ли?

+0

В C. C. нет методов, которые имеют только функции. –

+2

Выполнение 'float *' в 'double *' не будет работать для этого. В зависимости от того, что действительно делается, возможно: «double temp = * fOne; метод (& temp, ...); * fOne = temp; '. Вы можете обернуть это в функцию с именем 'void fmethod (float * pf);' –

+0

Если функция хочет 'double *', тогда вам нужно передать ей подлинный 'double *'. Вы можете конвертировать в/из 'float' вне функции. –

ответ

2

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

Но даже если вы знаете , что различные типы имеют такое же представление, преобразование указателя еще не безопасно! Из-за strict aliasing rule такие преобразования могут привести к некорректно сгенерированному коду компилятором, поскольку компилятор может предположить, что вы никогда не получите доступ к данным с помощью указателя неправильного типа. Таким образом, он может оптимизировать часть кода.

Это безопасно только бросить любой данный указатель:

  • К/с указатель, ссылающийся на тот же квалифицированного типа (*).
  • К указателю, указывающему на тот же тип, но с дополнительными определителями (*).
  • To/from void Указатель.
  • Пустой указатель.
  • К указателю на байтовые целочисленные типы, такие как char* или uint8_t*.

Все остальные случаи указателей на преобразования указателей являются ошибками и вызывают неопределенное поведение, как только вы получаете доступ к указанным данным. В том числе отливки отchar* до указателя на больший тип.


(*) Квалифицированные средства типа, тип с классификаторами, такими как const или volatile настоящее время. Например, безопасно конвертировать из int* в const int*, но никогда не наоборот.

+0

Обратите внимание, что это также «безопасно» (в том смысле, что вы имеете в виду), чтобы отбрасывать * назад * из символа 'char *' в исходный тип. –

+0

@OliverCharlesworth Ну ... безопасно конвертировать из, например, 'int *' в 'bananas *', а затем обратно в' int * ', без доступа к данным через указатель' bananas'. Почему ты это сделал, я понятия не имею. – Lundin

+0

Ну, в случае с символом 'char *', приведение к 'char *' явно разрешено для выполнения байтовых операций. Но в какой-то момент вам нужно вернуться к первоначальному типу, что также безопасно! –

Смежные вопросы