Почему Boost Format и printf ведут себя по-разному в одной и той же строке формата

Документация по формату Boostn гласит:

Одна из его целей — предоставить замену printf, что означает, что format может анализировать строку формата, предназначенную для printf, применять ее к заданным аргументам и давать тот же результат, что и printf.

Когда я сравниваю вывод boost:format и printf, используя одну и ту же строку формата, я получаю разные результаты. Онлайн-пример здесь

#include <iostream>
#include <boost/format.hpp>

int main()
{
    boost::format f("BoostFormat:%d:%X:%c:%d");

    unsigned char cr =65; //'A'
    int cr2i = int(cr);

    f % cr % cr % cr % cr2i;

    std::cout << f << std::endl;
    printf("Printf:%d:%X:%c:%d",cr,cr,cr,cr2i);
}

Результат:

BoostFormat: A:A:A:65

печать: 65:41:A:65

Разница в том, что я хочу отображать char как интегральный тип.

Почему такая разница? Это ошибка или нежелательное поведение?


person ToBe    schedule 20.11.2015    source источник


Ответы (2)


Это ожидаемое поведение.

В руководстве по ускорению написано о классической спецификации типа, которую вы используете:

Но классический флаг спецификации типа printf имеет более слабое значение в формате. Он просто устанавливает соответствующие флаги для внутреннего потока и/или параметры форматирования, но не требует, чтобы соответствующий аргумент имел определенный тип.

Также обратите внимание, что в вызове stdlib-printf все аргументы char автоматически преобразуются в int из-за вызова vararg. Таким образом, сгенерированный код идентичен:

printf("Printf:%d:%X:%c:%d",cr2i,cr2i,cr2i,cr2i);

Это автоматическое преобразование не выполняется с помощью оператора %.

person jofel    schedule 20.11.2015
comment
+1 Но, вау, это ужасно. Интересно, чем они мотивируют это? Кажется, они взяли формат стиля C (что не очень хорошо для начала), но все же не сделали его обратно совместимым. Например, выбрать худшее из обоих миров. - person user694733; 20.11.2015
comment
Спасибо за ваш ответ. Приятно знать, что это ожидаемое поведение, однако это было не то, что я ожидал. Здесь фактический тип имеет приоритет над спецификатором. Так что для char нет разницы между «%d» и «%c», странно. - person ToBe; 20.11.2015
comment
@ user694733: Boost.Format не может изменить перегрузку (во время компиляции) operator% на основе (во время выполнения) содержимого строки формата. Теперь вы можете скрыть проблему, но это значительно усложняет работу — вам придется реализовывать возможные сценарии перегрузки во время компиляции и выбирать правильный во время выполнения. Это также неэффективно с точки зрения пространства. - person MSalters; 20.11.2015
comment
@joefel В ​​своем коде вы на самом деле не написали код, который соответствует поведению того, что вы хотите вывести. Если вы хотите соответствовать поведению printf, вы должны были написать f % +cr % +cr % cr % +cr; - person Peter Nimmo; 13.09.2016
comment
Это использует унарный оператор + для выполнения интегрального повышения — см. msdn.microsoft.com/en-us/library/ewkkxkwb(d=hv.2,v=vs.140).aspx для получения подробной информации. - person Peter Nimmo; 13.09.2016

Дополнение к принятому ответу:

Это также происходит с аргументами типа wchar_t, а также unsigned short и других эквивалентных типов, что может быть неожиданным, например, при использовании членов структур в Windows API (например, SYSTEMTIME), которые по историческим причинам являются короткими целыми числами типа WORD. .

Если вы используете Boost Format в качестве замены printf и функций, подобных printf, в устаревшем коде, вы можете рассмотреть возможность создания оболочки, которая переопределяет оператор % таким образом, чтобы он преобразовывал

  • char и short до int
  • unsigned char и unsigned short до unsigned int

чтобы эмулировать поведение списков переменных аргументов C. Он по-прежнему не будет на 100% совместим, но большинство оставшихся несовместимостей на самом деле полезны для исправления потенциально небезопасного кода.

В более новом коде, вероятно, не следует использовать формат Boost, а должен использоваться стандарт std::format, который несовместим с printf.

person Florian Winter    schedule 14.04.2021