Странные символы в printf

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

Я пытаюсь понять, что вызывает следующую проблему. Я пишу свою функцию ведения журнала:

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);, я получу правильные результаты.

Я погуглил несколько реализаций (this или это) функций и функций ведения журнала, которые передают переменные параметры и вроде все делаю правильно.

Не могли бы вы подсказать мне, что я делаю не так?


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