C++ Dilinde std::format
- Yusuf Hançar
- Nov 6, 2024
- 6 min read
[[fill]align [sign][#][0][width][.precision][type]
C++ dilinde, formatlı bir çıktıyı işlemek uzun süredir karmaşık ve hata yapmaya açık bir konudur. C++20 öncesinde, geliştiriciler genellikle iki ana yönteme başvururdu: C tarzı biçimlendirme fonksiyonları (printf, sprintf, fprintf) veya C++ iostream kütüphanesinin sunduğu akım nesneleri. Ancak her iki yaklaşımın da bazı sınırlamaları vardı, bu da daha esnek ve modern bir çözüme olan ihtiyacı artırdı.
C Tarzı Biçimlendirme Fonksiyonları
C dilinde, printf, sprintf ve fprintf gibi fonksiyonlar, çeşitli yerlere formatlı çıktı vermeyi sağlıyordu. Örneğin:
sprintf ve snprintf kullanılarak formatlanmış bir metin oluşturulabilir ve bir string olarak saklanabilirdi; böylece tamsayılar, pointerlar gibi veri türleri kolayca formatlanabilirdi.
printf doğrudan standart çıktıya yazarken, fprintf formatlanmış bir metni dosyaya yazma imkanı sunuyordu.
Ancak, bu fonksiyonların C++ ile kullanılması bazı dezavantajlara yol açıyordu. Tür güvenliği eksikliği ve özelleştirme sınırlamaları, karmaşık biçimlendirme işlemlerini zorlaştırıyordu.
C++ iostream Kütüphanesi
C++ standart kütüphanesi ile, akım nesneleri (örneğin std::cout) ve format state desteği sunan iostream kütüphanesi tanıtıldı. Bu sınıfın operator<< fonksiyonları, akım nesnesinin format state'ine bağlı olarak çıktıyı kontrol ediyordu. Ancak, iostream biçimlendirmesi performans sınırlamaları ve esneklik eksiklikleri nedeniyle bazı durumlarda yetersiz kalabiliyordu.
std::format
C++20 ile gelen std::format kütüphanesi, yaygın olarak kullanılan fmt kütüphanesinden ilham alınarak geliştirilmiş modern bir formatlama çözümüdür. <format> include edilerek kullanılabilmektedir. std::format ile birlikte, derleme zamanında kontrol edilen tür güvenliği ve basit bir sözdizimi sayesinde verimli ve güvenli biçimlendirme sağlanmaktadır. Öne çıkan özellikleri şunlardır:
Compile-Time Safety: std::format ile sağlanan format string'leri derleme zamanında doğrulanır, bu sayede çalışma zamanı hataları azalır.
Exception Handling: Format uyumsuzlukları durumunda std::bad_alloc sınıfı türünden bir exception fırlatır.
Flexible Usage: std::format, hem standart çıktı hem de string formatlamada esnek ve sade bir yapı sunar; bu da modern C++ uygulamaları için ideal hale getirir.
template <class... Args>
std::string format(std::format_string<Args...> fmt, Args&&... args);
template <class... Args>
std::wstring format(std::wformat_string<Args...> fmt, Args&&... args);
template <class... Args>
std::string format(const std::locale& loc,
std::format_string<Args...> fmt, Args&&... args);
template <class... Args>
std::wstring format(const std::locale& loc,
std::wformat_string<Args...> fmt, Args&&... args);
int main()
{
int printf(const char* pfm, ...);
int sprintf(char* buf, const char* pfm, ...);
int fprintf(FILE*, const char* pfm, ...);
}
*****************************
AÇIKLAMA :
1- printf
* type safe değildir. (variadic fonksiyonların genel dezavantajıdır) (C dilinde variadic fonksiyon için elipsis atomundan önce bir parametre olmalıdır, C++ dilinde bu zorunlu değildir.)(Cdilinde variadic fonksiyonların çağrısında kaç arguman olduğunu iletmemiz gerekir.(sum(2, x, y) gibi ...
-> sprintf iostream'e göre daha hızlıdır.
* avantajı ise printf'in argumanlarla formatlama özelliklerini birbirinden ayırabiliriz.
*****************************
#include <format>
int main()
{
auto fmt = std::format("smart code");
}
*****************************
AÇIKLAMA : ifadenin türü std::string
*****************************
std::format specifier kullanabilmek için placeholder yapısını kullanılmalıdır.
printf fonksiyonunda % kullanılması yerine {} kullanılır.
#include <format>
int main()
{
std::format("{}");
}
#include <iostream>
#include <format>
int main()
{
std::string lang{ "cpp" };
int standart{ 20 };
std::cout << std::format("{} ile {} standartlari ile std::format kullanildi.", lang, standart);
}
*****************************
AÇIKLAMA : bu bir placeholder
*****************************
CEVAP : cpp ile 20 standartlari ile std::format kullanildi.
*****************************
positional index kullanılabilir.
int main()
{
std::string lang{ "cpp" };
int standart{ 20 };
std::cout << std::format("{} {} \n", lang, standart);
}
*****************************
AÇIKLAMA : önce lang sonra standart yazılır.
*****************************
CEVAP : cpp 20
*****************************
int main()
{
std::string lang{ "cpp" };
int standart{ 20 };
std::cout << std::format("{1} {0} \n", lang, standart);
}
*****************************
AÇIKLAMA : önce standart sonra lang yazılır.
*****************************
CEVAP : 20 cpp
*****************************
aynı "positional index" tekrar kullanılabilir.
int main()
{
std::string lang{ "cpp" };
int standart{ 20 };
std::cout << std::format("{1} {0} {1} \n", lang, standart);
}
*****************************
AÇIKLAMA : önce standart sonra lang sonra tekrar standart yazılır.
*****************************
CEVAP : 20 cpp 20
*****************************
Yazma alanı genişliği ve doldurma karakteri
int main()
{
int x{ 10 };
std::cout << std::format("|{{{}}}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|{10}|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:12}|", x);
}
*****************************
AÇIKLAMA : default alignment sağa dayalıdır.
*****************************
CEVAP :
| 10|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:>12}|", x);
}
*****************************
AÇIKLAMA : > ile sağa dayalı olarak belirtilir
*****************************
CEVAP :
| 10|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:<12}|", x);
}
*****************************
AÇIKLAMA : < ile sola dayalı olarak belirtilir
*****************************
CEVAP :
|10 |
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:^12}|", x);
}
*****************************
AÇIKLAMA : ^ ile ortalama olarak belirtilir
*****************************
CEVAP :
| 10 |
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:_>12}|", x);
}
*****************************
AÇIKLAMA : alt çizgi ekler
*****************************
CEVAP :
|__________10|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:_<12}|", x);
}
*****************************
AÇIKLAMA : alt çizgi ekler
*****************************
CEVAP :
|10____________|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:_^12}|", x);
}
*****************************
AÇIKLAMA : alt çizgi ekler
*****************************
CEVAP :
|______10______|
*****************************
Dinamik olarak yazma alanı genişliği belirlenebilir.
Default genişliği sıfırdır.
int main()
{
std::string str{ "cpp" };
std::cout << "yazma alani genisligi : ";
int wid{};
std::cin >> wid;
std::cout << std::format("|{:>{}}|", str, wid);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
yazma alani genisligi : 41
| cpp|
*****************************
int main()
{
std::string str{ "cpp" };
std::cout << "yazma alani genisligi : ";
int wid{};
std::cin >> wid;
std::cout << std::format("|{1:{0}}|", wid, str);
}
+ - işareti ekleme
int main()
{
int x{ 10 };
std::cout << std::format("|{:>12}|", x);
std::cout << std::format("|{:>12}|", -x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
| 10|| -10|
*****************************
int main()
{
int x{ 10 };
std::cout << std::format("|{:>+12}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
| +10|
*****************************
decimal yazdırmak için
int main()
{
int x{ 15 };
std::cout << std::format("|{:07d}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|00000015|
*****************************
octal yazdırmak için
int main()
{
int x{ 15 };
std::cout << std::format("|{:o}|", x);
}
*****************************
AÇIKLAMA : octal
*****************************
CEVAP :
|17|
*****************************
hex yazdırmak için
int main()
{
int x{ 26 };
std::cout << std::format("|{:07X}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|000001A|
*****************************
xhex yazdırmak için
int main()
{
int x{ 26 };
std::cout << std::format("|{:#07X}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|0X000001A|
*****************************
int main()
{
int x{ 26 };
std::cout << std::format("|{:#07x}|", x);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|0X000001a|
*****************************

general |
|
fixed |
|
scientific |
|
hexfloat |
|
int main()
{
std::cout << std::fixed;
if (std::cout.flags() & std::ios::fixed)
{
std::cout << "fixed set" << "\n";
}
else
{
std::cout << "fixed unset" << "\n";
}
if (std::cout.flags() & std::ios::scientific)
{
std::cout << "scientific set" << "\n";
}
else
{
std::cout << "scientific unset" << "\n";
}
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
fixed set
scientific unset
*****************************
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << "|" << std::fixed << d << "<|\n";
}
*****************************
AÇIKLAMA : fixed
*****************************
CEVAP :
gercek sayi gir: 5.4
|5.400000<|
*****************************
#include <iostream>
#include <iomanip>
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << "|" << std::scientific << d << "<|\n";
}
*****************************
AÇIKLAMA : scientific
*****************************
CEVAP :
gercek sayi gir: 5.4
|5.400000e+00<|
*****************************
std::format ile de yapılabilir
default formatı general

int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << std::format("|{}|\n", d);
}
*****************************
AÇIKLAMA : scientific
*****************************
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << std::format("|{:g}|\n", d);
}
*****************************
AÇIKLAMA : general
*****************************
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << std::format("|{:e}|\n", d);
}
*****************************
AÇIKLAMA : scientific
*****************************
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << std::format("|{:f}|\n", d);
}
*****************************
AÇIKLAMA : fixed
*****************************
int main()
{
double d{};
std::cout << "gercek sayi gir: ";
std::cin >> d;
std::cout << std::format("|{:a}|\n", d);
}
*****************************
AÇIKLAMA : hexfloat
*****************************
boolean formatlama
default true ya da false şeklindedir.
int main()
{
std::cout << std::format("|{}|\n", true);
std::cout << std::format("|{}|\n", 10 > 15);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|true|
|false|
*****************************
int main()
{
std::cout << std::format("|{:d}|\n", true);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP : |1|
*****************************
int main()
{
std::cout << std::format("|{:#b}|\n", true);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP : |0b1|
*****************************
& adres için default yok
int main()
{
int x{ 15 };
std::cout << std::format("|{}|\n", &x);
}
*****************************
AÇIKLAMA : error: static assertion failed: std::formatter must be specialized for each type being formatted
*****************************
CEVAP : error
*****************************
int main()
{
int x{ 15 };
std::cout << std::format("|{}|\n", static_cast<void*>(&x));
}
*****************************
AÇIKLAMA : legal
*****************************
int main()
{
int x{ 15 };
std::cout << std::format("|{:#x}|", reinterpret_cast<uintptr_t>(&x));
}
*****************************
AÇIKLAMA : legal
*****************************
int main()
{
std::cout << std::format("|{}|", nullptr);
std::cout << std::format("|{:p}|", nullptr);
}
*****************************
AÇIKLAMA : legal
*****************************
CEVAP : |0x0||0x0|
*****************************
string nesneler icin default hizalama sola dayalıdır (int için default sağa dayalıdır)
int main()
{
std::string str{ "smartcode" };
std::cout << std::format("|{:6}|", str);
}
*****************************
AÇIKLAMA :
*****************************
CEVAP :
|smartcode |
*****************************
[.precision]
int main()
{
std::string str{ "cpp20" };
std::cout << std::format("|{:12.3}|", str);
}
*****************************
AÇIKLAMA : .3 precision değeridir.
*****************************
CEVAP :
|cpp |
*****************************

Comentários