개요
fmt는 오픈 소스 C++ 포맷팅 라이브러리로, C++20 std::format과 C++23 std::print를 구현합니다. Python과 유사한 포맷 구문과 위치 인자를 제공하며, 사용자 정의 타입, Unicode, chrono 및 범위를 지원합니다. 이 라이브러리는 타입 안전성과 높은 성능을 갖추고 있으며, 선택적으로 단일 헤더 파일 모드를 사용할 수 있습니다.
README 미리보기
\n\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)\n[](\nhttps://issues.oss-fuzz.com/issues?q=title:fmt%20cc:victor.zverovich@gmail.com)\n[](\nhttps://www.bestpractices.dev/projects/8880)\n[](\nhttps://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)\n[](https://stackoverflow.com/questions/tagged/fmt)\n[](https://novaukraine.org/)\n\n**{fmt}** is an open-source formatting library providing a fast and safe\nalternative to C stdio and C++ iostreams.\n\n[Documentation](https://fmt.dev)\n\n[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html)\n\nQ&A: ask questions on [StackOverflow with the tag\nfmt](https://stackoverflow.com/questions/tagged/fmt).\n\nTry {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).\n\n# Features\n\n- Simple [format API](https://fmt.dev/latest/api/) with positional\n arguments for localization\n- Implementation of [C++20\n std::format](https://en.cppreference.com/w/cpp/utility/format) and\n [C++23 std::print](https://en.cppreference.com/w/cpp/io/print)\n- [Format string syntax](https://fmt.dev/latest/syntax/) similar\n to Python\'s\n [format](https://docs.python.org/3/library/stdtypes.html#str.format)\n- Fast IEEE 754 floating-point formatter with correct rounding,\n shortness and round-trip guarantees using the\n [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm\n- Portable Unicode support\n- Safe [printf\n implementation](https://fmt.dev/latest/api/#printf-api)\n including the POSIX extension for positional arguments\n- Extensibility: [support for user-defined\n types](https://fmt.dev/latest/api/#formatting-user-defined-types)\n- High performance: faster than common standard library\n implementations of `(s)printf`, iostreams, `to_string` and\n `to_chars`, see [Speed tests](#speed-tests) and [Converting a\n hundred million integers to strings pFAQ (5)
문제 해결{fmt}가 최신 이모지와 CJK 문자를 `{:?}` 및 vector/range 출력에서 \Uxxxxxxxx로 이스케이프하는 이유는 무엇이며, 어떻게 해결할 수 있나요?
이 문제는 fmt::detail::is_printable이 Unicode 13.0 데이터로부터 생성되었기 때문에 발생합니다. Unicode 14.0–17.0에서 추가된 코드 포인트(예: 🫠 U+1FAE0 및 CJK Extensions H/I/J)는 할당되지 않은 것(Cn)으로 잘못 분류되어 이스케이프됩니다. {fmt}를 Update is_printable to Unicode 17.0 수정이 포함된 릴리스 또는 커밋으로 업데이트하세요. 포크를 유지 관리하는 경우, python3 support/printable.py를 실행하여(스크립트의 Unicode 버전/데이터 URL이 고정되어 있다면 해당 부분을 업데이트한 후) Unicode 17.0.0 UnicodeData.txt로부터 테이블을 다시 생성하고, 생성된 is_printable 코드를 교체한 다음 다시 빌드하세요. 이후 fmt::print("{:?}\n", "🫠")는 "\U0001fae0" 대신 "🫠"를 출력합니다.
문제 해결/W4로 컴파일할 때 fmt/ranges.h에서 발생하는 MSVC 경고 C4702(도달할 수 없는 코드)를 수정하려면 어떻게 해야 하나요?
이는 fmt 12.2.0의 range formatter로 인해 발생하는 알려진 MSVC 오탐지입니다. include/fmt/ranges.h에서 formatter() 생성자를 패치하여 set_brackets()가 else 분기에 들어가도록 하세요:
FMT_CONSTEXPR formatter() {
if FMT_CONSTEXPR20 (range_format_kind<R, Char>::value != range_format::set)
return;
else
range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
}
그런 다음 다시 빌드하세요. 임시 해결 방법으로 #pragma warning(disable: 4702)을 사용하여 서드파티 헤더에 대한 경고를 비활성화하거나 /wd4702로 컴파일할 수 있지만, 패치를 적용하거나 수정 사항이 포함된 fmt 릴리스로 업그레이드하는 것이 권장됩니다.
문제 해결release 태그가 참조하는 commit을 checkout할 수 없는 Git submodule은 어떻게 수정하나요?
서브모듈을 업데이트하기 전에 모든 서브모듈에서 태그를 가져옵니다:
git submodule foreach --recursive 'git fetch --tags'
git submodule update --recursive
이 작업은 서브모듈이 구성된 브랜치에서 도달할 수 없는 커밋의 태그를 가리킬 때 필요합니다. 근본적인 해결책은 관리자가 유지 관리되는 브랜치에 릴리스 태그를 지정하거나 별도의 릴리스 브랜치를 만드는 것입니다.
문제 해결`FMT_USE_LOCALE=0`일 때 fmt의 `{:L}` 지정자가 쉼표 그룹화 또는 전역 로케일을 사용하도록 수정하려면 어떻게 해야 하나요?
이것은 fmt 버그입니다: 로케일 지원이 비활성화된 상태에서 {:L}은 정수에 대해 무시되었고, 부동소수점 값에 대해서는 하드코딩된 쉼표 폴백이 사용되었으며, 일부 chrono 포매터는 전역 로케일인 std::locale()을 참조했습니다. issue #4941에 대한 수정이 포함된 fmt 릴리스로 업데이트하거나, 업스트림 변경 사항 "Use classic locale grouping without locale support" 및 "Don't require std::locale in chrono.h when FMT_USE_LOCALE is 0"을 적용하세요. 수정 후에는 L이 허용되지만 classic/C 로케일 의미를 사용합니다: fmt::format("{:L}", 1234567)은 1234567로 유지되고, fmt::format("{:L}", 1234.5)는 쉼표 그룹화 없이 1234.5를 반환합니다. fmt를 포함하기 전에 매크로를 정의하세요. 예를 들어 C++에서는 #include <fmt/...> 앞에 #define FMT_USE_LOCALE 0을, CMake에서는 target_compile_definitions(my_target PRIVATE FMT_USE_LOCALE=0)을 지정한 후 다시 빌드하세요. 영향을 받는 버전에서는 해결 방법으로 포맷 문자열에서 L을 제거하세요. 로케일별 숫자나 chrono 이름이 필요하면 FMT_USE_LOCALE=1로 빌드하고 원하는 std::locale을 fmt::format에 명시적으로 전달하세요.
문제 해결std::array에서 파생된 타입과 함께 fmt::format_as를 사용할 때 발생하는 Clang 15–20 세그멘테이션 폴트를 해결하는 방법
이 타입은 std::array를 상속하기 때문에 range이면서 동시에 format_as 오버로드도 가지고 있으므로, {fmt}의 range 포매터와 format_as 지원이 모호해집니다. Clang은 모호성을 보고하는 대신 크래시합니다. 해당 타입에 대해 명시적인 fmt::formatter 특수화를 제공하여 이를 해결하세요:
#include <fmt/format.h>
template <>
struct fmt::formatter<Sha256Hash> : fmt::formatter<std::string>
{
auto format(const Sha256Hash& h, fmt::format_context& ctx) const
{
return fmt::formatter<std::string>::format(format_as(h), ctx);
}
};
또는, 기본 range 포매팅을 원한다면 format_as를 제거하거나, 타입이 range로 인식되지 않도록 std::array를 public으로 상속하는 대신 컴포지션을 사용하세요. Clang 세그폴트 자체는 Clang 15부터 20까지의 컴파일러 버그이지만, 이 모호성이 근본적인 소스 코드 문제입니다.