2015-06-04 3 views
0

Я пытаюсь понять понятия указателя в глубину. В следующем коде,Разница между (float *) & * (float *) в C

#include <stdio.h> 
int main() 
{ 
    int i = 10; 
    int *iptr = &i; 
    printf("(float)* : %f\n", (float)*iptr); 
    printf("(float*) : %f\n", (float*)iptr); 
    printf("*(float*) : %f\n", *(float*)iptr); 
    return 0; 
} 

выход:

(float)* : 10.000000 
(float*) : 10.000000 
*(float*) : 0.000000 

Я также получил предупреждение за тип отливка (float*).
Мне трудно даже проанализировать разницу. Если кто-нибудь может помочь мне проанализировать, что такое точное использование всех трех, было бы полезно.

+1

Второй 'printf()' не должен компилироваться. –

+7

@iharob Да, должно быть, несоответствия спецификатора (и нарушения псевдонимов) - это неопределенное поведение, но не ограничение ограничений. –

+0

Он скомпилирован с предупреждающим сообщением @iharob – Preethi

ответ

4

Разница в том,

  1. Вы разыменовании int и приведения его к float в

    printf("(float)* : %f\n", (float)*iptr); 
    

    , который прекрасно.

  2. Вы заливка int указателя на float указатель, и печать float указателя с "%f" спецификатором не определенно поведение, правильный спецификатор для печати указателей "%p", так

    printf("(float*) : %f\n", (float*)iptr); 
    

    неправильно, это должны быть

    printf("(float*) : %p\n", (void *) iptr); 
    

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

  3. Вы заливка int указателя на float и разыменованиях полученного float указателя, хотя он будет violate strict aliasing rules в

    printf("(float*) : %f\n", *(float*)iptr); 
    

    который также неопределенного поведение

+0

По-прежнему нужно использовать его 'void *' для соответствия '% p'. –

+0

@iharob, понятный до того, что вы объяснили. Несмотря на то, что это неопределенное поведение, я не получал никаких ошибок или даже предупреждений. Интересно, как это возможно для «* (float *) ptr». Является ли адрес, который указывает iptr перед изменением? Не удалось точно понять, как я получаю 0.000000 для «* (float *)» – Preethi

+0

Когда происходит неопределенное поведение, поведение является _unpredictable_ и необъяснимым. –

3

Первые правильно ,

i является int переменной, и iptr указатель на этот int.

  1. (float)*iptr: *iptr разыменовывает iptr, который возвращает int. Затем int преобразуется во временный float, содержащий такое же значение. И что float используется printf.

  2. *(float*)iptr: Попытки бросить указатель-to int в указатель-to float. Это недопустимо и должно вызывать предупреждение или ошибку компилятора.Он создает указатель с тем же адресом, но с типом, говорящим, что он указывает значение float.

    Оператор * затем разыгрывает его, поэтому int считывается, как если бы он был float. Таким образом, результат float будет недействительным, и это может привести к segfault, потому что float s длиннее, чем int s, поэтому он считывает больше памяти, чем выделено для int.

  3. (float*)iptr: Та же проблема, но она не разыменования (недействительных) указатель и передает указатель-to float в printf, вместо float. Но printf ожидает float. Некоторые компиляторы также должны вызывать предупреждение/ошибку, потому что строка формата указывает, какие типы значений ожидаются.

    Если спецификатор формата указывает %p, он ожидает указатель (void*, float* или любой другой). Затем он распечатает адрес, а не значение, на которое оно указывает. Это может быть полезно при отладке, например.

+0

Предупреждение, которое генерирует компилятор на втором printf: 'warning: format '% f' ожидает аргумент типа 'double', но аргумент 2 имеет тип 'float *' [-Wformat = ] 'это предупреждение не означает, что неверно преобразование из' int * 'в' float * ', но printf ожидает значение float, а не значение указателя. Компилятор только говорит, что параметр не того же типа, который объявлен в строке формата. –

+0

Но для * (float *) iptr - я не обнаружил ошибки или даже предупреждения о том же, и он печатает 0.000000 (для% f) (может быть значением по умолчанию для float по моим знаниям) @tmlen – Preethi

+0

@tmlen , ... Другими словами, если (во втором 'printf') вы используете'% p' вместо '% f', то компилятор не дает никаких предупреждений, хотя в этом случае в объявлении' (float *) 'нет смысл! ... Тогда проблема не в неопределенном поведении; неопределенное поведение может повлиять на возможное присвоение I.E .: (относится к коду в вопросе) 'i = * (float *) iptr;', но компилятор не сигнализирует о каком-либо предупреждении! –

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