Код (Text): typedef int (__stdcall * _sprintf)(char *buf, char *fmt, ...); HMODULE hNtdll = GetModuleHandle("ntdll.dll"); _sprintf s_printf = (_sprintf) GetProcAddress(hNtdll, "sprintf"); double fl = 1.7320534; s_printf(buffer, "float: %f", fl); В буфере имеем "float: x[" Если более традиционным способом: Код (Text): double fl = 1.7320534; sprintf(buffer, "float: %f", fl); то прога вообще вылетает молча на sprintf. При этом на других спецификаторах, типа d, s, c работают оба варианта. Что здесь неправильно? P.S. Если скомпилировать как консольную прогу, то вылазит ошибка floating point not loaded (во втором варианте).
Код (Text): #include <stdio.h> int main() { char buf[256]; float fp = 1.756456[b]f[/b]; sprintf(buf, "float: %f", fp); printf("%s\n", buf); } Код (Text): C:\Temp>float.exe float: 1.756456
я именно с 1.756456f и начинал. Компилятор vc++7.0 Компилятор не при чём: он своё дело сделал: код вызова корректный. Попробовал на всякий случай ml.exe - та же хрень (в буфере мусор вместо числа). Как с double, так и с float. Все спецификаторы, кроме плавающей запятой (%f %g %e) работают. Писать свою функцию что-ли?
cresta Используй из msvcrt.dll -------------------------- Поотлаживал, силно удивился. %f, %g, %e (насчет %g не уверен) действительно не обрабатываются. После определения % и убедившись, что следующий символ - f, процедура берет адрес BaseProcessInitPostImport (из kernel32.dll) откуда-то из стековых переменных и парсит его... как ANSI строку! ППЦ.
KeSqueer Всё-таки нашлась нормальная sprintf Действительно из msvcrt работает нормально. Правда довольно медленная функция, (в 4 раза медленее чем FpuFLtoA из fpu.lib/masm), но зато форматировать можно. ОК. Спасибо.
cresta Видимо, ntdll!sprintf по функционалу такая же, как и user32!wsprintf — т.е., с плавающими числами не работает.
IceStudent Может быть и так, а как же тогда либсовая? Она ведь тоже фактически получается не работает с %f, хотя в msdn черным по белому сказано, что работает, даже пример есть.
msvcrt.dll и libcmt/libc.lib - это не одно и то же. C msvcrt.dll я работаю через GetModuleHandle/GetProcAddress HMODULE hMsvcrt = GetModuleHandle("msvcrt.dll"); _sprintf s_printf = (_sprintf) GetProcAddress(hMsvcrt, "sprintf"); s_printf(buffer, "float: %f", 1.2345); и так все работает нормально. Если я делаю sprintf(buffer, "float: %f", 1.2345); то здесь работает совсем другой код. Тот, который попадает в exe из libc.lib. И этот код косячит. Вот про это я и говорил либсовая sprintf.
Единственная разница только в формате — dll или lib. Код-то один и тот же (почти). Не заметил такого. Код (Text): int main() { char buffer[64]; sprintf(buffer, "float: %f", 1.2345); printf(buffer); return 0; }
Это почему? Ни в sprintf.c, ни в output.c я не заметил препроцессорных блоков, относящихся к различиям компиляции статической и динамической библитеки CRT.
Функция достаточно путаная, чтобы отслеживать всё в дизассемблере, но то что они разные (sprintf в msvcrt.dll и в libc.lib) - у меня никаких сомнений нет. Принимая одинаковые данные, они дают разные результаты. Были бы одинаковыми - результаты тоже были бы одинаковы.
Ну не знаю, давай конкретный пример кода и параметры компиляции — в общем, всё, чтобы можно было предметно сравнивать. Т.к. вышеприведённый в #12 код у меня даёт одинаковые результаты: Код (Text): #cl /nologo /MD ctest.cpp ctest.cpp #ctest i = 1.500000 #cl /nologo ctest.cpp ctest.cpp #ctest i = 1.500000
Вот полный комплект, с сорцом, готовым exe-шником и bat-файлом. Что за беда с этими аттачами????? Опять нет кнопки прикрепления аттача Даже при редактировании сообщения не появляется. Как прикрепить аттач ???? Вот тут подвесил: http://hooliganos.jino-net.ru/img/forice.zip
cresta Тот, который попадает в exe из libc.lib. И этот код косячит Попробуй вместо Код (Text): ... #pragma comment(linker, "/MERGE:.rdata=.text") //#pragma comment(linker, "/subsystem:console") #pragma comment(linker, "/subsystem:windows") #pragma comment(linker, "/entry:main") ... написать Код (Text): ... #pragma comment(linker, "/MERGE:.rdata=.text") #pragma comment(linker, "/subsystem:console") //#pragma comment(linker, "/subsystem:windows") //#pragma comment(linker, "/entry:main") ... получишь два MessageBox'а с _одинаковыми_ сообщениями. Afaik проблема в #pragma comment(linker, "/entry:main"). Ты не даешь шанса crt инициализироваться.
cresta + по поводу typedef int (__stdcall * _sprintf)(char *buf, char *fmt, ...); Afaik подпрограммы с переменным числом параметров используют соглашение вызова __cdecl. Посмотри на генерируемый код, у msvc хватает ума игнорировать твой __stdcall.