Странни знаци в printf

Моята среда: Xcode5, iOS, Objective-C/Objective-C++ mix.

Опитвам се да разбера какво причинява следващия проблем. Пиша собствена функция за регистриране:

int _me_log(const char *fmt, ...) {

va_list args;
va_start(args, fmt);

char *c = va_arg(args, char *);

char *message = NULL;

printf(fmt, args);

int n = asprintf(&message, fmt, args);

if (n != -1 && message != NULL) {
 //do something with 'message' like writing to file, etc.
 UPDATE:
//we need to handle memory created for 'message' storage.
free(message); 
}
va_end(args);

return n;

}

Тогава го наричам така:

_me_log("socket %s did open", "Socket: 0x1fd1c880");

И вместо правилен резултат socket Socket: 0x1fd1c880 did open получавам някакви безсмислици като този socket \\323\331/ did open в този ред printf(fmt, args);.

Ако го нарека по този начин printf("%s", c);, получавам правилни резултати.

Търсих в Google няколко реализации (това или това ) от функции за регистриране и функции, които предават променливи параметри и изглежда, че правя всичко правилно.

Бихте ли ми предложили какво правя грешно?


person user1264176    schedule 12.11.2013    source източник
comment
Изглежда, че искате vasprintf вместо asprintf.   -  person Holly    schedule 12.11.2013


Отговори (2)


Имате правилната идея да използвате va_list тук, но ако работите с va_list, трябва да използвате vasprintf вместо asprintf:

int _me_log(const char *fmt, ...)
{
    va_list args;
    char *message = NULL;
    int n;

    va_start(args, fmt);
    n = vasprintf(&message, fmt, args);

    if (n != -1 && message != NULL) {
        // ... use message ...
    }
    free(message);
    va_end(args);

    return n;
}

За всяка рутина от семейството printf има вариант, който приема va_list вместо променливия аргумент ... и чието име е с префикс буквата v, например:

int printf(const char *format, ...);
int vprintf(const char *format, va_list ap);

Тези процедури съществуват, за да можете да напишете свой собствен (не-макро) обвивка за xprintf.

person M Oehm    schedule 12.11.2013
comment
Благодаря, вече добавих коментар към предишния отговор. Приемам вашия отговор, защото той дава директен отговор на моя въпрос и код в него. отговорът на trojanfoe също е правилен. - person user1264176; 12.11.2013
comment
@trojanfoe, ако имате предвид изтичане на „съобщение“, тогава, разбира се, ще се справя с това. Пропуснах го за краткост на кода. - person user1264176; 12.11.2013
comment
Актуализиран въпрос с освобождаване на паметта за „съобщение“. Само в случай, че някой го копира/постави. - person user1264176; 12.11.2013
comment
Добре, това има повече смисъл, но обаждането до free(), което сега е в този отговор, е на грешното място. - person trojanfoe; 12.11.2013
comment
@trojanfoe: Разбира се, буферът за съобщения трябва да бъде освободен. User1264176 ме изпревари в редактирането на отговора. Благодаря, че коригирахте това. - person M Oehm; 12.11.2013
comment
@trojanfoe: Това е на грешното място само ако vasprintf гарантира, че буферът е NULL ако и само ако се връща -1. Законно е (ако е ненужно) или free(NULL). - person M Oehm; 12.11.2013
comment
И какво ще направи free(NULL)? - person trojanfoe; 12.11.2013
comment
@trojanfoe: Няма да направи нищо. Вероятно е така, за да не се налага да проверявате за NULL в клиентския код. Но съм съгласен с вас по принцип: ако условието беше if (message) ..., щеше да е по-чисто да освободите буфера в края на блока if. - person M Oehm; 12.11.2013
comment
А, добре - на някои системи, които ще се взривят - не под OSX/iOS предполагам. - person trojanfoe; 12.11.2013

Изглежда като много сложно изпълнение. Опитвам:

int _me_log(const char *fmt, ...) {
    int ret = 0;
    va_list va;
    va_start(va, fmt);
    ret = vprintf(fmt, va);
    va_end(va);

    putc('\n', stdout);
    return ret;
}

Но, разбира се, това не се различава от printf(), с изключение на налагането на нов ред.

person trojanfoe    schedule 12.11.2013
comment
Сега виждам грешката си. Не можете да извикате printf с va_list като параметър като този printf(fmt, va);. Вместо това трябва да извикате vprintf(). Благодаря. - person user1264176; 12.11.2013