Все компилится. Работает. Выводит 7739.376.
Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно.
Допустим. Удаляем определение прототипа ф-ции float schet(void) из проги.
Компилируем. Слушаем надоедливые ворчания компилятора.
Запускаем исплоняемый файл и получаем ... -1.999!!!
Почему?!
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re: Преобразования типов, прототипы и т.д. по списку...
M>Все компилится. Работает. Выводит 7739.376. M>Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно. M>Допустим. Удаляем определение прототипа ф-ции float schet(void) из проги. M>Компилируем. Слушаем надоедливые ворчания компилятора. M>Запускаем исплоняемый файл и получаем ... -1.999!!! M>Почему?!
Наверно фишка тут в том, что если функция описана после main, то ее нужно объявить
Re: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, maximum28, Вы писали:
M>Все компилится. Работает. Выводит 7739.376. M>Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно.
Но ооочень рекомендуется M>Допустим. Удаляем определение прототипа ф-ции float schet(void) из проги. M>Компилируем. Слушаем надоедливые ворчания компилятора. M>Запускаем исплоняемый файл и получаем ... -1.999!!! M>Почему?!
Потому что функции в C по умолчанию считаются как возвращающие int ну а дальше тебе printf наколбасил
... << RSDN@Home 1.1.4 beta 3 rev. 190>>
Re[2]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, migel, Вы писали:
M>Здравствуйте, maximum28, Вы писали:
M>>Все компилится. Работает. Выводит 7739.376. M>>Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно.
Странный термин, не натыкался раньше на такой... определение прототипа — то есть объявление функции?
Если да, то я в шоке.
Как это не обязательно??? А как линкер узнает, что типа "есть такая функция..."?
M>Но ооочень рекомендуется
не просто рекомендуется, а строго обязательно.
Иначе, (если я неправильно понимаю термин "определение прототипа") просьб ане бить ногами в живот =)
Перед тем, как улучшиться, ситуация ухудшается. (из законов Мерфи)
Re[2]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, migel, Вы писали:
M>Потому что функции в C по умолчанию считаются как возвращающие int ну а дальше тебе printf наколбасил
Точнее, там происходит следующее:
1) если прототип объявлен float schet(void)
printf("%f", schet()) здесь 4-байтовый float расширяется до 8-байтового double
"%f" печатает double в фиксированном формате
2) если не объявлен
прототип измышляется как int schet(void)
то, что sizeof(int)==sizeof(float), это нам крупно повезло сейчас...
но чуть позже — крупно не везёт
printf("%f", schet()) здесь 4-байтовый int (содержащий, на самом деле, float) оставляется как есть
"%f" печатает double, у которого 4 байта из того самого int'а, а ещё 4 байта — мусор на стеке.
3) наконец, если извратиться и написать
printf("%f", (double)schet())
то мы возьмём битовое представление float'а и это здоровенное целое число переведём в double.
Перекуём баги на фичи!
Re: Преобразования типов, прототипы и т.д. по списку...
maximum28,
> Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно.
Но начиная с 99-го, по крайней мере, объявление функции должно быть в области видимости в точке вызова. Это означает, что компиляция приведенного примера с удалением предварительного объявления функции schet() компилятором "нового" C должна завершаться выдачей сообщения об ошибке. Хотя прототип функции, действительно, может быть опущен (с точки зрения C это означает возможность не указывать список параметров в объявлении функции).
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Кодт, Вы писали:
К>3) наконец, если извратиться и написать К>printf("%f", (double)schet()) К>то мы возьмём битовое представление float'а и это здоровенное целое число переведём в double.
без объявления прототипа компилятор сгенерирует перевод int в double, что так же не спасет
Re[4]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, vdimas, Вы писали:
V>без объявления прототипа компилятор сгенерирует перевод int в double, что так же не спасет
Ничего он не сгенерирует.
printf это функция с эллипсом (...), а компилятор придерживается такого правила:
— целочисленные (в т.ч. bool и enum) расширяет до ближайшего подходящего из {int, long, __int64}
— плавающие — до double
— указатели — как есть, т.е. void*
— структуры — по идее, это ill-formed, хотя пёс его знает (под рукой Стандарта нет). VC пихает их по значению, выравнивая на 4.
Если функция без прототипа, то её результат трактуется как int. Соответственно, на стеке окажутся 4 байта (если 32-битная платформа).
Перекуём баги на фичи!
Re[5]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, migel, Вы писали:
M>>Потому что функции в C по умолчанию считаются как возвращающие int ну а дальше тебе printf наколбасил
К>Точнее, там происходит следующее:
К>1) если прототип объявлен float schet(void) К>printf("%f", schet()) здесь 4-байтовый float расширяется до 8-байтового double К>"%f" печатает double в фиксированном формате
Неправда ваша! Для вывода double надо буковку "лы"-латинскую прописывать.
К>2) если не объявлен К>прототип измышляется как int schet(void) К>то, что sizeof(int)==sizeof(float), это нам крупно повезло сейчас... К>но чуть позже — крупно не везёт К>printf("%f", schet()) здесь 4-байтовый int (содержащий, на самом деле, float) оставляется как есть К>"%f" печатает double, у которого 4 байта из того самого int'а, а ещё 4 байта — мусор на стеке.
int выводится как float — полная фигня выводится! К>3) наконец, если извратиться и написать К>printf("%f", (double)schet()) К>то мы возьмём битовое представление float'а и это здоровенное целое число переведём в double.
Не — 'f' — это float.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, LaptevVV, Вы писали:
К>>"%f" печатает double в фиксированном формате LVV>Неправда ваша! Для вывода double надо буковку "лы"-латинскую прописывать. LVV>Не — 'f' — это float.
Увы, увы. %f — это именно double, а %Lf — long double.
Легко убедиться, что ... принимает вещественные числа именно как double.
#include <stdarg.h>
#include <stdio.h>
void foo(int b, ...)
{
double x,y,z;
va_list va;
va_start(va,b);
x = va_arg(va,double);
y = va_arg(va,float);
z = va_arg(va,double);
printf("%f\n%f\n%f\n", x, y, z);
}
main()
{
foo(1, 12.34, (float)12.34, 12.34);
/* результат выглядит так:
*
* 12.340000
* 0.000000
* какой-то немыслимый крендильон
*
* это означает, что, начиная со второго параметра, мы считали из стека не то, что записали
* но мы же писали float? ан нет, мы записали double
*/
}
Впрочем, не могу сказать — прописано ли это Стандартом или 32-битными компиляторами. Во всяком случае, здравому смыслу не противоречит.
В том, что это не MS-specific — уверен.
Про здравый смысл:
1) Дело в том, что вещественные литералы вида 123.45, 123.45e67 — имеют в С/С++ тип double. Чтобы написать float литерал, надо справа дописать букву F: 123.45F. А зачем нам лишняя работа?
2) Расширение целых чисел до int, а вещественных — до double — позволяет наименее геморройно передавать произвольные числа через эллипс.
Перекуём баги на фичи!
Re[5]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, LaptevVV, Вы писали:
К>>>"%f" печатает double в фиксированном формате LVV>>Неправда ваша! Для вывода double надо буковку "лы"-латинскую прописывать. LVV>>Не — 'f' — это float. К>Увы, увы. %f — это именно double, а %Lf — long double.
Это большая. А там еще маленькая есть — я все это буквально вчера проверял, поэтому все еще помню
К>Легко убедиться, что ... принимает вещественные числа именно как double. К>1) Дело в том, что вещественные литералы вида 123.45, 123.45e67 — имеют в С/С++ тип double. Чтобы написать float литерал, надо справа дописать букву F: 123.45F. А зачем нам лишняя работа?
Ну, это по умолчанию — это да. Но там же явный возврат float из функции. К>2) Расширение целых чисел до int, а вещественных — до double — позволяет наименее геморройно передавать произвольные числа через эллипс.
Ну, это тож понятно.
Но посмотри всеж printf — вывод double — это lf (не Lf)
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[6]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, LaptevVV, Вы писали:
К>>Увы, увы. %f — это именно double, а %Lf — long double. LVV>Это большая. А там еще маленькая есть — я все это буквально вчера проверял, поэтому все еще помню
Нет. Стандарт Си не определяет применение l совместно с f.
Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
Re[3]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Кодт, Вы писали:
К>2) если не объявлен К>прототип измышляется как int schet(void) К>то, что sizeof(int)==sizeof(float), это нам крупно повезло сейчас... К>но чуть позже — крупно не везёт К>printf("%f", schet()) здесь 4-байтовый int (содержащий, на самом деле, float) оставляется как есть К>"%f" печатает double, у которого 4 байта из того самого int'а, а ещё 4 байта — мусор на стеке.
Кстати, еще не факт, что в данном случае произойдет переинтерпретация float в int. Во многих архитектурах для возвращаемых из функций скаляров используются регистры, а сами регистры могут быть разделены для целых чисел и для вещественных. Соответственно, вызываемая функция, зная, что ей полагается возвратить float или double, оставляет результат в "вещественном" регистре (например, ST(0)), а вызывающая, не зная объявления, предполагает, что тип возврата — int, и забирает результат из "целого" регистра (например, AX), где лежит "мусор".
Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
Re[5]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Кодт, Вы писали:
К>Если функция без прототипа, то её результат трактуется как int.
Здесь есть терминологическая путаница. В Си (до стандарта 1999 года) можно было использовать необъявленную функцию, и тогда компилятор предполагал, что она не имеет прототипа и возвращает результат типа int. Прототип — это перечень формальных параметров функции. Функция может быть объявлена, как не имеющая прототипа, но при этом иметь тип возвращаемого значения, отличный от int.
Здравствуйте, LaptevVV, Вы писали:
К>>Увы, увы. %f — это именно double, а %Lf — long double. LVV>Это большая. А там еще маленькая есть — я все это буквально вчера проверял, поэтому все еще помню
На каком компиляторе? Для 16-битных приложений, вполне возможно, расширять до double является роскошью, поэтому там могут быть отступления от Стандарта.
LVV>Но посмотри всеж printf — вывод double — это lf (не Lf)
Может быть, long double ?
Перекуём баги на фичи!
Re[2]: Преобразования типов, прототипы и т.д. по списку...
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>maximum28,
>> Если вспомнить теорию Си, то вообще-то, определение прототипа функции не обязятельно.
ПК>Но начиная с 99-го, по крайней мере, объявление функции должно быть в области видимости в точке вызова. Это означает, что компиляция приведенного примера с удалением предварительного объявления функции schet() компилятором "нового" C должна завершаться выдачей сообщения об ошибке. Хотя прототип функции, действительно, может быть опущен (с точки зрения C это означает возможность не указывать список параметров в объявлении функции).
Компилятор GCC одной из последних версий
Re[3]: Преобразования типов, прототипы и т.д. по списку...
Если говорить о стандартах, то еще надо смотреть как компилируется файл — как С или как С++. Потому как С++ включает в себя С89, а С99 это уже отдельная ветвь. По крайней мере так года три назад было.
А насчет модификаторов, из Шилдта (который заявлен как один из членов ANSI/ISO принимавших стандарт):
scanf : %f == float, %Lf == long double, %lf == double
printf: %f == double, %Lf == long double, %lf == не указано (сказано, что "l" применяется для d,i,o,u,x,n,c,s) но видимо либо double, либо long double
Мафиозная диктатура это нестабильность. Если не мафиозная диктатура, то Конституция и демократия.
Re[4]: Преобразования типов, прототипы и т.д. по списку...