sprintf и "f"

Тема в разделе "LANGS.C", создана пользователем cresta, 9 окт 2007.

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Код (Text):
    1.     typedef int (__stdcall * _sprintf)(char *buf, char *fmt, ...);
    2.  
    3.     HMODULE hNtdll = GetModuleHandle("ntdll.dll");
    4.     _sprintf s_printf = (_sprintf) GetProcAddress(hNtdll, "sprintf");
    5.    
    6.     double fl = 1.7320534;
    7.     s_printf(buffer, "float: %f", fl);
    В буфере имеем "float: x["
    Если более традиционным способом:

    Код (Text):
    1.     double fl = 1.7320534;
    2.     sprintf(buffer, "float: %f", fl);
    то прога вообще вылетает молча на sprintf.

    При этом на других спецификаторах, типа d, s, c работают оба варианта.
    Что здесь неправильно?

    P.S.
    Если скомпилировать как консольную прогу, то вылазит ошибка floating point not loaded (во втором варианте).
     
  2. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Код (Text):
    1. #include <stdio.h>
    2.  
    3. int main() {
    4.     char buf[256];
    5.     float fp = 1.756456[b]f[/b];
    6.  
    7.     sprintf(buf, "float: %f", fp);
    8.     printf("%s\n", buf);
    9. }
    Код (Text):
    1. C:\Temp>float.exe
    2. float: 1.756456
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    nester7

    Это не принципиально, 1.756456f то же самое, что и 1.756456
     
  4. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Я в курсе, просто проверь. А что за компилятор?
     
  5. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    я именно с 1.756456f и начинал. Компилятор vc++7.0
    Компилятор не при чём: он своё дело сделал: код вызова корректный. Попробовал на всякий случай ml.exe - та же хрень (в буфере мусор вместо числа). Как с double, так и с float.
    Все спецификаторы, кроме плавающей запятой (%f %g %e) работают.
    Писать свою функцию что-ли?
     
  6. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    cresta
    Используй из msvcrt.dll

    --------------------------
    Поотлаживал, силно удивился. %f, %g, %e (насчет %g не уверен) действительно не обрабатываются. После определения % и убедившись, что следующий символ - f, процедура берет адрес BaseProcessInitPostImport (из kernel32.dll) откуда-то из стековых переменных и парсит его... как ANSI строку! ППЦ.
     
  7. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    KeSqueer

    Всё-таки нашлась нормальная sprintf :) Действительно из msvcrt работает нормально.
    Правда довольно медленная функция, (в 4 раза медленее чем FpuFLtoA из fpu.lib/masm), но зато форматировать можно.

    ОК. Спасибо.
     
  8. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    cresta
    Видимо, ntdll!sprintf по функционалу такая же, как и user32!wsprintf — т.е., с плавающими числами не работает.
     
  9. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    IceStudent

    Может быть и так, а как же тогда либсовая? Она ведь тоже фактически получается не работает с %f, хотя в msdn черным по белому сказано, что работает, даже пример есть.
     
  10. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Это которая? CRT? Ты же сам сказал, что
     
  11. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    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.
     
  12. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Единственная разница только в формате — dll или lib. Код-то один и тот же (почти).

    Не заметил такого.
    Код (Text):
    1. int main()
    2. {
    3.     char buffer[64];
    4.     sprintf(buffer, "float: %f", 1.2345);
    5.     printf(buffer);
    6.     return 0;
    7. }
     
  13. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    "Почти" не считается :) Код действительно разный. Одинаково только название функции.
     
  14. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Это почему? Ни в sprintf.c, ни в output.c я не заметил препроцессорных блоков, относящихся к различиям компиляции статической и динамической библитеки CRT.
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Функция достаточно путаная, чтобы отслеживать всё в дизассемблере, но то что они разные (sprintf в msvcrt.dll и в libc.lib) - у меня никаких сомнений нет. Принимая одинаковые данные, они дают разные результаты. Были бы одинаковыми - результаты тоже были бы одинаковы.
     
  16. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Ну не знаю, давай конкретный пример кода и параметры компиляции — в общем, всё, чтобы можно было предметно сравнивать. Т.к. вышеприведённый в #12 код у меня даёт одинаковые результаты:
    Код (Text):
    1. #cl /nologo /MD ctest.cpp
    2. ctest.cpp
    3.  
    4. #ctest
    5. i = 1.500000
    6. #cl /nologo ctest.cpp
    7. ctest.cpp
    8.  
    9. #ctest
    10. i = 1.500000
     
  17. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вот полный комплект, с сорцом, готовым exe-шником и bat-файлом.


    Что за беда с этими аттачами?????
    Опять нет кнопки прикрепления аттача :dntknw: Даже при редактировании сообщения не появляется.

    Как прикрепить аттач ????

    Вот тут подвесил:

    http://hooliganos.jino-net.ru/img/forice.zip
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
  19. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta
    Тот, который попадает в exe из libc.lib. И этот код косячит
    Попробуй вместо
    Код (Text):
    1. ...
    2. #pragma comment(linker, "/MERGE:.rdata=.text")
    3. //#pragma comment(linker, "/subsystem:console")
    4. #pragma comment(linker, "/subsystem:windows")
    5. #pragma comment(linker, "/entry:main")
    6. ...
    написать
    Код (Text):
    1. ...
    2. #pragma comment(linker, "/MERGE:.rdata=.text")
    3. #pragma comment(linker, "/subsystem:console")
    4. //#pragma comment(linker, "/subsystem:windows")
    5. //#pragma comment(linker, "/entry:main")
    6. ...
    получишь два MessageBox'а с _одинаковыми_ сообщениями.

    Afaik проблема в #pragma comment(linker, "/entry:main"). Ты не даешь шанса crt инициализироваться.
     
  20. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta
    + по поводу typedef int (__stdcall * _sprintf)(char *buf, char *fmt, ...);
    Afaik подпрограммы с переменным числом параметров используют соглашение вызова __cdecl. Посмотри на генерируемый код, у msvc хватает ума игнорировать твой __stdcall.