Как передать переменное количество аргументов printf/sprintf

Картинка не стоит тысячи слов.

Некоторые картинки могут стоить тысячи слов. Большинство из них нет. Этот старый банальный афоризм по большей части не соответствует действительности и является жалким оправданием для многих ленивых менеджеров, которые не хотят читать тщательно созданные отчеты и документацию, говоря: «Мне нужно, чтобы вы показали меня на диаграмме».

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

В частности, помеченные пузырьки, связанные с линиями, бесполезны, если линии немаркированы и необъяснены, и / или если каждая строка имеет различное значение вместо обозначения одних и тех же отношений (если они не отличаются друг от друга каким-либо образом). Если ваши строки иногда указывают на отношения, а иногда указывают на действия, а иногда указывают на то, что время прошло, вы действительно охвачены надеждой.

Каждый хороший программист знает, что вы используете инструмент, подходящий для данной задачи, верно? Не все системы лучше всего определены и документированы в картинках. Языки графических спецификаций, которые могут автоматически превращаться в доказуемо корректный, исполняемый код или что-либо еще, что является впечатляющей идеей, если такие вещи существуют. Используйте их, когда это уместно, не для всего под солнцем. Диаграммы сущности-отношения великолепны. Но не все можно суммировать на картине.

Примечание: таблица может быть на вес золота. Но таблица - это не то же самое, что таблица . И снова, хорошо составленный короткий прозаический абзац может быть гораздо более подходящим для работы под рукой.

76
задан hippietrail 31 March 2011 в 12:31
поделиться

7 ответов

void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

Если вы хотите манипулировать строкой перед ее отображением и действительно хотите, чтобы она сначала сохранялась в буфере, используйте vsnprintf вместо vsprintf . vsnprintf предотвратит случайную ошибку переполнения буфера.

143
ответ дан 24 November 2019 в 11:12
поделиться

Использование функций с эллипсами небезопасно. Если производительность не критична для функции журнала, рассмотрите возможность использования перегрузки оператора, как в boost :: format. Вы можете написать что-то вроде этого:

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

class formatted_log_t {
public:
    formatted_log_t(const char* msg ) : fmt(msg) {}
    ~formatted_log_t() { cout << fmt << endl; }

    template <typename T>
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }

protected:
    boost::format                fmt;
};

formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }

// use
int main ()
{
    log("hello %s in %d-th time") % "world" % 10000000;
    return 0;
}

Следующий пример демонстрирует возможные ошибки с помощью многоточия:

int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.
4
ответ дан 24 November 2019 в 11:12
поделиться

Вы ищете вариативные функции . printf () и sprintf () являются функциями с переменным числом аргументов - они могут принимать переменное количество аргументов.

Это влечет за собой в основном следующие шаги:

  1. Первый параметр должен указывать некоторое количество следующих параметров. Итак, в printf () символ " "формат" дает это указание - если у вас есть 5 спецификаторов формата, тогда он будет искать еще 5 аргументов (всего 6 аргументов). Первый аргумент может быть целым числом (например, "myfunction (3, a, b, c ) "где" 3 "означает" 3 аргумента)

  2. Затем выполните цикл и извлеките каждый последующий аргумент, используя функции va_start () и т. д. ".

Есть много руководств о том, как это сделать - удачи!

3
ответ дан 24 November 2019 в 11:12
поделиться

Мне следовало бы прочитать больше о существующих вопросах по переполнению стека.

C ++ Передача переменного числа аргументов - аналогичный вопрос. У Майка Ф. есть следующее объяснение:

Нет способа вызвать (например) printf не зная, сколько аргументов вы переходите к нему, если вы не хотите попасть в непослушный и непереносимый уловки.

Обычно используемое решение - всегда предоставляйте альтернативную форму vararg, поэтому printf имеет vprintf, который принимает на место va_list из .... Версии ... просто оболочки для версий va_list

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

void Error(const char* format, ...)
{
    char dest[1024 * 16];
    va_list argptr;
    va_start(argptr, format);
    vsprintf(dest, format, argptr);
    va_end(argptr);
    printf(dest);
}
3
ответ дан 24 November 2019 в 11:12
поделиться

взгляните на vsnprintf как это будет делать то, что вы хотите http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

вам нужно сначала инициализировать массив va_list arg, а затем вызвать его.

Пример из эта ссылка: / * пример vsprintf * /

#include <stdio.h>
#include <stdarg.h>

void Error (char * format, ...)
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer, 255, format, args);


  //do something with the error

  va_end (args);
}
31
ответ дан 24 November 2019 в 11:12
поделиться

Взгляните на пример http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/ , они передают количество аргументов методу, но вы можете опустить это и изменить код соответствующим образом (см. пример).

0
ответ дан 24 November 2019 в 11:12
поделиться

Простой пример ниже. Обратите внимание, что вы должны передать буфер большего размера и проверить, достаточно ли он большой

void Log(LPCWSTR pFormat, ...) 
{
    va_list pArg;
    va_start(pArg, pFormat);
    char buf[1000];
    int len = _vsntprintf(buf, 1000, pFormat, pArg);
    va_end(pArg);
    //do something with buf
}
2
ответ дан 24 November 2019 в 11:12
поделиться