Вот мой код, я точно не знаю, почему это происходит:
#include <stdio.h>
void foo(float *);
int main()
{
int i = 10, *p = &i;
foo(&i);
}
void foo(float *p)
{
printf("%f\n", *p);
}
ВЫХОД :
0
Вы вызываете функцию, ожидающую float*
с указателем на int. В C ++ это ошибка, и ваш код не компилируется. В C вы, скорее всего, все равно получите предупреждение и неопределенное поведение.
Как уже было сказано, вы передаете адрес целочисленной переменной как адрес числа с плавающей запятой одинарной точности.
В идеале такое неявное преобразование должно быть запрещено, но в зависимости от компилятора и того, является ли оно чистым C или C ++, оно может просто привести к предупреждению.
Но почему он печатает ровно 0?
Именно из-за того, как FPN одинарной точности представлены в памяти:
(1 bit of sign)|(8 bits of biased exponent)|(23 bits of significand(mantissa))
10 в двоичном
0|0000 0000|000 0000 0000 0000 0000 0000 1010
Итак, когда интерпретируется как значение с плавающей точкой:
(sign = 0)(biased exponent = 0)(significand = 10)
смещенный показатель — нормальный показатель плюс 127 — http://en.wikipedia.org/wiki/Exponent_bias
Для расчета стоимости будем использовать следующую формулу:
floatValue = ((sign) ? (-1) : (1)) * pow(2, normalExponent) * significand
Это даст:
floatValue = 1 * pow (2, 0 - 127) * 10 = 10 * 2 in pow -127.
Это очень небольшое число, которое при представлении с использованием %f
спецификатор превращается в "0"
строка.
РЕШЕНИЕ:
Чтобы решить эту проблему, просто используйте временную переменную и явное приведение перед вызовом foo
:
int main()
{
int i = 10;
float temp = (float)i;
foo(&temp);
}
void foo(float *p)
{
printf("%f\n", *p);
}
Постскриптум Чтобы избежать подобных проблем в будущем, всегда устанавливайте свой компилятор на максимально реалистичный уровень предупреждений и всегда разбирайтесь с каждым из них перед запуском приложения.
Потому что вы объявляете свой целочисленный объект и объект указателя на int
а также int *
вместо float
а также float *
,
Вы не можете передать объект типа int *
к функции, которая ожидает аргумент типа float *
без явного преобразования.
Изменить:
int i = 10, *p = &i;
в
float i = 10, *p = &i;
Обратите внимание, что ваш p
указатель в main
не используется, и его объявление может быть удалено.
Вы по существу приводите указатель на int к указателю на число с плавающей точкой. Это допустимо, но BAD — printf пытается понять память, зарезервированную для int, как число с плавающей запятой (которое будет по-разному представлено в памяти), и результаты не определены.
Вы пытаетесь прочитать область, выделенную для переменной типа int, и пытаетесь прочитать как float.
Поплавки написаны как мантисса и показатель степени. В зависимости от представления в памяти, вы, вероятно, загружаете экспоненту со своей «10», в то время как мантисса остается нулевой. В результате 0 ^ 10 (или как это интерпретируется) равно 0.
Это связано с тем, что вы передаете целое число в функцию, и вы ловите с типом данных с плавающей точкой.
Когда вы его скомпилируете, вы получите предупреждение, если включите флаги предупреждения.
root@sathish1:~/My Docs/Programs# cc float1.c
float1.c: In function ‘main’:
float1.c:11:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
float1.c:3:6: note: expected ‘float *’ but argument is of type ‘int *’
Это ясно говорит вам, что вы делаете.
Ваша функция исключает float *
, но вы проходите int *
, Таким образом, при печати он будет искать соответствующую область памяти и попытаться распечатать ее. Но переменные типа float хранятся в стандарте IEEE 754, но функция получает адрес целого числа, поэтому она попытается распечатать данные в этой ячейке памяти (int
не хранится в стандарте IEEE 754). Таким образом, результат не определен.