Результат не определен.
Я просто спрашиваю это с теоретической точки зрения.
Полный крис отличный ответ а>:
То, что происходит в вашем printf, не определено, но это может быть очень похоже на приведенный ниже код (это зависит от фактической реализации varargs, IIRC).
Отказ от ответственности: следующее объяснение того, что может произойти в случае неопределенного поведения на одной платформе, больше похоже на "как если бы это сработало", чем истинное/действительное описание, которое всегда происходит на всех платформах. я>
Дайте определение «неопределенное»?
Представьте себе следующий код:
int main()
{
int i = 10 ;
void * pi = &i ;
double * pf = (double *) pi ; /* oranges are apples ! */
double f = *pf ;
/* what is the value inside f ? */
return 0;
}
Здесь, поскольку ваш указатель на double (т. е. pf
) указывает на адрес, содержащий целочисленное значение (т. е. i
), то, что вы получите, не определено и, скорее всего, является мусором.
Я хочу увидеть, что внутри этого воспоминания!
Если вы действительно хотите увидеть, что может скрываться за этим мусором (при отладке на некоторых платформах), попробуйте следующий код, в котором мы будем использовать объединение для имитации участка памяти, куда мы будем записывать данные типа double или int:
typedef union
{
char c[8] ; /* char is expected to be 1-byte wide */
double f ; /* double is expected to be 8-bytes wide */
int i ; /* int is expected to be 4-byte wide */
} MyUnion ;
Поле f
и i
используются для установки значения, а поле c
используется для просмотра (или изменения) памяти, байт за байтом.
void printMyUnion(MyUnion * p)
{
printf("[%i %i %i %i %i %i %i %i]\n"
, p->c[0], p->c[1], p->c[2], p->c[3], p->c[4], p->c[5], p->c[6], p->c[7]) ;
}
приведенная выше функция распечатает структуру памяти, байт за байтом.
Приведенная ниже функция напечатает расположение памяти различных типов значений:
int main()
{
/* this will zero all the fields in the union */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
printMyUnion(&myUnion) ; /* this should print only zeroes */
/* eg. [0 0 0 0 0 0 0 0] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.i = 10 ;
printMyUnion(&myUnion) ; /* the representation of the int 10 in the union */
/* eg. [10 0 0 0 0 0 0 0] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.f = 10 ;
printMyUnion(&myUnion) ; /* the representation of the double 10 in the union */
/* eg. [0 0 0 0 0 0 36 64] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.f = 3.1415 ;
printMyUnion(&myUnion) ; /* the representation of the double 3.1415 in the union */
/* eg. [111 18 -125 -64 -54 33 9 64] */
return 0 ;
}
Примечание. Этот код был протестирован на Visual C++ 2010.
Это не означает, что это будет работать так (или вообще) на вашей платформе, но обычно вы должны получить результаты, аналогичные приведенным выше.
В конце концов, мусор - это просто шестнадцатеричный набор данных в памяти, на который вы смотрите, но воспринимаемый как некоторый тип.
Поскольку большинство типов имеют различное представление данных в памяти, просмотр данных в любом другом типе, кроме исходного, обязательно приведет к мусорным (или не таким уж мусорным) результатам.
Ваш printf вполне может вести себя так и, таким образом, попытаться интерпретировать необработанный фрагмент памяти как двойной, когда он изначально был установлен как int.
P.S.: Обратите внимание, что поскольку int и double имеют разный размер в байтах, мусор становится еще сложнее, но в основном это то, что я описал выше.
Но я хочу напечатать int как двойной!
Серьезно?
Helios предложил решение .
int main()
{
int x=10;
printf("%f",(double)(x));
return 0;
}
Давайте посмотрим на псевдокод, чтобы увидеть, что передается в printf:
/* printf("...", [[10 0 0 0]]) ; */
printf("%i",x);
/* printf("...", [[10 0 0 0 ?? ?? ?? ??]]) ; */
printf("%f",x);
/* printf("...", [[0 0 0 0 0 0 36 64]]) ; */
printf("%f",(double)(x));
Приведения предлагают другой макет памяти, эффективно изменяя целочисленные данные «10» на двойные данные «10.0».
Таким образом, при использовании "%i" ожидается что-то вроде [[?? ?? ?? ??]], а для первого printf получить [[10 0 0 0]] и правильно интерпретировать его как целое число.
При использовании "%f" ожидается что-то вроде [[?? ?? ?? ?? ?? ?? ?? ??]], и получить на второй printf что-то вроде [[10 0 0 0]], пропущенных 4 байта. Таким образом, 4 последних байта будут случайными данными (вероятно, байтами «после» [[10 0 0 0]], то есть что-то вроде [[10 0 0 0 ?? ?? ?? ??]]
В последнем printf приведение изменило тип и, следовательно, представление памяти на [[0 0 0 0 0 0 36 64]] и printf будет правильно интерпретировать его как двойное.
person
paercebal
schedule
26.07.2012
(float)x
.%lf
этоdouble
. - person chris   schedule 26.07.2012%f
равноdouble
, потому что значенияfloat
повышаются доdouble
при передаче через многоточие - person qehgt   schedule 26.07.2012%f
и%lf
разделены. - person chris   schedule 26.07.2012