C++: как добраться, fprintf заканчивается как станд.:: представьте w/o в виде строки sprintf

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

18
задан feedc0de 12 September 2016 в 08:59
поделиться

6 ответов

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

Работы как очарование для меня - и внешние зависимости могли быть хуже (очень стабильная библиотека)

Отредактированный: добавление примера, как использовать повышение:: формат вместо printf:

sprintf(buffer, "This is a string with some %s and %d numbers", "strings", 42);

было бы что-то вроде этого с повышением:: библиотека формата:

string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);

Hope это помогает разъяснить использование повышения:: формат

я использовал повышение:: формат как sprintf / printf замена в 4 или 5 приложениях (пишущий отформатированные строки в файлы или пользовательский вывод к файлам журнала) и никогда не имел проблемы с различиями в формате. Могут быть некоторые (более или менее неясные) спецификаторы формата, которые являются по-другому - но у меня никогда не было проблемы.

По контрасту у меня были некоторые спецификации формата, которые я не мог действительно сделать с потоками (так же, как я помню)

13
ответ дан 30 November 2019 в 06:12
поделиться

Вот идиома, которую я люблю за то, что то, что он делал функциональность идентичной 'sprintf', но возвратил станд.:: строка, и неуязвимый для проблем переполнения буфера. Этот код является частью проекта с открытым исходным кодом, который я пишу (лицензия BSD), таким образом, все не стесняются использовать это, как Вы желаете.

#include <string>
#include <cstdarg>
#include <vector>
#include <string>

std::string
format (const char *fmt, ...)
{
    va_list ap;
    va_start (ap, fmt);
    std::string buf = vformat (fmt, ap);
    va_end (ap);
    return buf;
}



std::string
vformat (const char *fmt, va_list ap)
{
    // Allocate a buffer on the stack that's big enough for us almost
    // all the time.
    size_t size = 1024;
    char buf[size];

    // Try to vsnprintf into our buffer.
    va_list apcopy;
    va_copy (apcopy, ap);
    int needed = vsnprintf (&buf[0], size, fmt, ap);
    // NB. On Windows, vsnprintf returns -1 if the string didn't fit the
    // buffer.  On Linux & OSX, it returns the length it would have needed.

    if (needed <= size && needed >= 0) {
        // It fit fine the first time, we're done.
        return std::string (&buf[0]);
    } else {
        // vsnprintf reported that it wanted to write more characters
        // than we allotted.  So do a malloc of the right size and try again.
        // This doesn't happen very often if we chose our initial size
        // well.
        std::vector <char> buf;
        size = needed;
        buf.resize (size);
        needed = vsnprintf (&buf[0], size, fmt, apcopy);
        return std::string (&buf[0]);
    }
}

РЕДАКТИРОВАНИЕ: когда я написал этот код, я понятия не имел, что это потребовало соответствия C99 и что Windows (а также более старый glibc) имел другое vsnprintf поведение, в котором это возвращается-1 для отказа, а не категорической меры того, сколько пространства необходимо. Вот мой пересмотренный код, мог все просматривать его и если Вы будете думать, что он в порядке, то я отредактирую снова для создания этого единственной стоимостью перечисленный:

std::string
Strutil::vformat (const char *fmt, va_list ap)
{
    // Allocate a buffer on the stack that's big enough for us almost
    // all the time.  Be prepared to allocate dynamically if it doesn't fit.
    size_t size = 1024;
    char stackbuf[1024];
    std::vector<char> dynamicbuf;
    char *buf = &stackbuf[0];
    va_list ap_copy;

    while (1) {
        // Try to vsnprintf into our buffer.
        va_copy(ap_copy, ap);
        int needed = vsnprintf (buf, size, fmt, ap);
        va_end(ap_copy);

        // NB. C99 (which modern Linux and OS X follow) says vsnprintf
        // failure returns the length it would have needed.  But older
        // glibc and current Windows return -1 for failure, i.e., not
        // telling us how much was needed.

        if (needed <= (int)size && needed >= 0) {
            // It fit fine so we're done.
            return std::string (buf, (size_t) needed);
        }

        // vsnprintf reported that it wanted to write more characters
        // than we allotted.  So try again using a dynamic buffer.  This
        // doesn't happen very often if we chose our initial size well.
        size = (needed > 0) ? (needed+1) : (size*2);
        dynamicbuf.resize (size);
        buf = &dynamicbuf[0];
    }
}
39
ответ дан 30 November 2019 в 06:12
поделиться

Можно использовать станд.:: строка и iostreams с форматированием, таким как setw () вызов и другие в iomanip

1
ответ дан 30 November 2019 в 06:12
поделиться

Следующее могло бы быть альтернативным решением:

void A::printto(ostream outputstream) {
    char buffer[100];
    string s = "stuff";
    sprintf(buffer, "some %s", s);
    outputstream << buffer << endl;
    b.printto(outputstream);
}

(B::printto подобный), и определяют

void A::print(FILE *f) {
    printto(ofstream(f));
}

string A::to_str() {
    ostringstream os;
    printto(os);
    return os.str();
}

, Конечно, необходимо действительно использовать snprintf вместо sprintf для предотвращения переполнения буфера. Вы могли также выборочно изменить более рискованный sprintfs на < < формат, чтобы быть более безопасным и все же измениться как можно меньше.

1
ответ дан 30 November 2019 в 06:12
поделиться

Необходимо попробовать библиотеку Loki заголовочный файл SafeFormat ( http://loki-lib.sourceforge.net/index.php?n=Idioms.Printf ). Это подобно библиотеке формата строки повышения, но сохраняет синтаксис printf (...) функционирует.

я надеюсь, что это помогает!

1
ответ дан 30 November 2019 в 06:12
поделиться

Это о сериализации? Или печать надлежащего? Если первый, рассмотрите повышение:: сериализация также. Это - все о "рекурсивной" сериализации объектов и подобъекта.

0
ответ дан 30 November 2019 в 06:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: