sprintf и "f"

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

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Убедил. Нужен WinMain (для subsystem:windows). Этот чертов crt уже начинает нервировать :)
    О typedef: первоначально я его использовал при вызове sprintf из ntdll, и почему-то был уверен, что в ntdll все функции stdcall.
    Оказалось нет. Ну и по наследству typedef достался msvcrt.dll :)

    И тогда ещё один вопрос по sprintf:

    Код (Text):
    1. void foo (char *dest, char *fmt, ...){
    2.     //как передать входные параметры в sprintf?
    3.     sprintf (dest, fmt, ?????????);
    4. }
    Если бы sprintf принимал третьим параметром va_list, я бы ему сформировал и отдал бы его(как в случае с wvsprintf)..
    Но он хочет набор аргументов. va_arg я тоже использовать не могу, т.к. va_arg'у нужны параметры одного типа, если я правильно понимаю. Т.е. либо все int, либо все char* и т.д.
    А у меня параметры могут быть разного типа.
    Можно попробовать через asm оттянуть стек вниз, скопировать входные параметры к новой вершине стека+4, в вершину положить адрес возврата и далее jmp на sprintf.
    Но это как-то слишком экстравагантно. Должен быть способ без таких выкрутасов.
     
  2. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Думаю, что по-другому никак. Тут даже дело не в типах параметров (кажется, они могут быть любого типа), а в том, что их надо как-то передать, т.е. вызов sprintf должен содержать вполне определенное число параметров. Поэтому придется делать что-то в этом роде:

    Код (Text):
    1.  push param1
    2.  push param2
    3.  ...
    4.  push paramN
    5.  push fmt
    6.  call sprintf
    7.  add esp, N
     
  3. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    cresta
    Т.е. у foo и sprintf одинаковые аргументы? Тогда почему просто jmp sprintf не сделать?
    [+]
    Или помимо вызова sprintf в foo происходят еще какие-то действия? Тогда IMHO это неосуществимо, т.к. за стеком постоянно следить надо - что и когда туда положли и забрали.
     
  4. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Код (Text):
    1. #define lsys_log_error(level, ...)                                          \
    2.             if (cfg->debug_level >= level)                                 \
    3.                 lsys_log_error_core(level, __VA_ARGS__)
    4.  
    5.                
    6. #define lsys_log_debug(...)                                                 \
    7.             lsys_log_error_core(LSYS_LOG_DEBUG, __VA_ARGS__)
     
  5. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Код (Text):
    1. Variadic Macros
    2.  
    3. Variadic macros are function-like macros that contain a variable number of arguments.
    4.  
    5. Remarks
    6. To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments. __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.
    7.  
    8. The C Standard specifies that at least one argument must be passed to the ellipsis, to ensure that the macro does not resolve to an expression with a trailing comma. The Visual C++ implementation will suppress a trailing comma if no arguments are passed to the ellipsis.
    9.  
    10. Example
    11.   Copy Code
    12. // variadic_macros.cpp
    13. #include <stdio.h>
    14. #define EMPTY
    15.  
    16. #define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
    17. #define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
    18. #define CHECK3(...) { printf(__VA_ARGS__); }
    19. #define MACRO(s, ...) printf(s, __VA_ARGS__)
    20.  
    21. int main() {
    22.    CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)\n");
    23.    CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)\n");   // won't print
    24.  
    25.    CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)\n");   // won't print
    26.    CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)\n");
    27.  
    28.    // always invokes printf in the macro
    29.    CHECK3("here %s %s %s", "are", "some", "varargs3(5)\n");
    30.  
    31.    MACRO("hello, world\n");
    32.    // MACRO("error\n", EMPTY);   would cause C2059
    33. }
    34.  
    35.  
    36. Output
    37.  
    38. here are some varargs1(1)
    39. here are some varargs2(4)
    40. here are some varargs3(5)
    41. hello, world
    Кажется, это только в макросах применимо.
     
  6. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Обычно этого хватает.
     
  7. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    _vscprintf
     
  8. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    IceStudent
    _vscprintf принимает va_list _вторым_ аргуметом, но ход мыслей правилен. ;)

    cresta
    Если бы sprintf принимал третьим параметром va_list
    Есть такая в crt - vsprintf (ANSI C compatibility). Использовать так
    Код (Text):
    1. void foo (char *dest, char *fmt, ...){
    2.   va_list ap;
    3.   va_start(ap, fmt);
    4. //    sprintf (dest, fmt, ?????????);
    5.   vsprintf(dest, fmt, ap);
    6.   va_end(ap);
    7. }
    ps ты заботишся о размере буфера для dest?
     
  9. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    q_q
    Ээ, да, спутал. _vscprintf это не то.
     
  10. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    KeSqueer
    За стеком следить не так и сложно. Просто хочется готового решения :)

    q_q
    Проглядел vsprintf... Попробовал кучу других XXXprintf в поисках принимающей va_list и поддерживающей спецификатор %f, а именно vsprintf выпала из поля зрения.

    Возвращаясь к crt: может ли msvcrt полноценно заменить libcmt? Сделал так:

    Код (Text):
    1.     #pragma comment(linker, "/nodefaultlib:LIBC")
    2.     #pragma comment(linker, "/nodefaultlib:LIBCMT /NODEFAULTLIB:OLDNAMES")
    3.     #pragma comment(linker, "/defaultlib:MSVCRT")
    пока ничего криминального не вижу, программа вроде работает, но может есть какие-то подводные камни? Кроме необходимости наличия msvcrt.dll ?
     
  11. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Я уже говорил выше о идентичности. То есть, для тебя, как для разработчика, разица только одна: в типе линковки (динамической или статической). Со всеми вытекающими последствиями (скорость вызовов, размер программы, etc.).
     
  12. cresta

    cresta Active Member

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

    Спасибо всем.