Может кто-нибудь объяснить, почему мой первый выводит 0, но после * p = 6,35 он может вывести 6,35? - PullRequest
0 голосов
/ 27 августа 2018
#include <stdio.h>
void print_binary(int n);
void test();

int main(){
    test();
    return 0;
}
void print_binary (int n){
    unsigned int mask = 0;
    mask = ~mask^(~mask >> 1);
    for (; mask != 0; mask >>= 1){
        putchar ((n & mask) ? '1' : '0');
    }
}
void test(){
    int x;
    float *p;
    p = (float *) &x;
    printf ("x init value :%d\n", x);
    printf ("addr x and p are %p %p\n", &x, p);
    printf ("print x in bit ");
    print_binary(x);
    printf ("\n");//00000000000000000000000000000000
    *p = 6.35;
    printf ("print x in bit ");
    print_binary(x);
    printf ("\n");//01000000110010110011001100110011
    printf ("x after 6.35 value :%d\n", x);//1087058739
    printf ("call1 x:%.100f\n", x);//0.0000000.....
    printf ("x:%d\n", x);//1087058739
    printf ("call2 x:%f\n", x);//0.000000
    printf ("p:%f\n", *p);//6.350000
    printf ("call3 x:%f\n", x);//6.350000
}

Результаты:

x init value :0                                                                                                                                                                    
addr x and p are 0x7ffc37d5ba8c 0x7ffc37d5ba8c                                                                                                                                     
print x in bit 00000000000000000000000000000000                                                                                                                                    
print x in bit 01000000110010110011001100110011                                                                                                                                    
x after 6.35 value :1087058739                                                                                                                                                     
call1 x:0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                     
x:1087058739                                                                                                                                                                       
call2 x:0.000000                                                                                                                                                                   
p:6.350000                                                                                                                                                                         
call3 x:6.350000

Я печатаю свои x после *p = 6.35;, и в памяти получаем 01000000110010110011001100110011, это правильное число согласно IEEE754, можеткто-то объяснит, почему мой первый printf ("call1 x:%.100f\n", x) напечатал меня 0.00..., но после того, как я printf ("p:%f\n", *p), он может напечатать 6.35?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

По вашим тегам (преобразование типов и неявное преобразование) вы ожидаете, что произойдет какое-то преобразование типов.Это не так.

Доступ к памяти с неверно напечатанным указателем не приводит к какому-либо преобразованию.Это просто интерпретирует память по-другому.Это включает в себя нарушение строгих правил псевдонимов, вызывающих неопределенное поведение.

И когда вы используете

printf ("call1 x:%.100f\n", x);//0.0000000.....

, вы обманываете свой компилятор.Вы обещаете передать значение double (спецификатор формата %f), которое обычно содержит 8 байтов, но затем вы передаете только 4 байта целого числа.Несоответствие в спецификаторе типа и типе параметра приводит к неопределенному поведению, и все ожидания безрезультатны.

Затем вы снова используете

printf ("p:%f\n", *p);//6.350000

, который прекрасно работает, когда вы предоставляете правильный двойной параметр.(здесь единственное неявное преобразование типов)

При компиляции этого кода ваш компилятор должен выводить некоторые предупреждения.И вы всегда должны слушать компилятор и разрешать предупреждения.

0 голосов
/ 27 августа 2018

Разыменование p - это неопределенное поведение , поскольку p указывает не на float, а на int (см., Например, Что такое правило строгого наложения имен)? ).

Кроме того, попытка печати int со спецификатором формата "%f" является неопределенным поведением, поскольку этот спецификатор формата ожидает double (см.например. Почему printf ("% f", 0) дает неопределенное поведение? ).

Итак, вы не можете полагаться ни на какое поведение этого кода - все возможно.

На практике, вероятно, происходит то, что компилятор решил переместить *p = 6.35; вправо до printf ("p:%f\n", *p);.

...