top of page

C++ Dilinde std::format

  • Writer: Yusuf Hançar
    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:

  1. 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.

  2. Exception Handling: Format uyumsuzlukları durumunda std::bad_alloc sınıfı türünden bir exception fırlatır.

  3. 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|
*****************************

ree


general

  • General formatlama, sayının büyüklüğüne bağlı olarak fixed veya scientific notasyonda gösterilmesine otomatik olarak karar verir. Küçük sayılar için fixed, çok büyük veya çok küçük sayılar için ise scientific notasyon kullanılır.

fixed

  • Fixed formatlama, ondalıklı sayıları sabit ondalık (fixed) notasyonda gösterir. Bilimsel notasyon olmadan, belirli bir ondalık basamak hassasiyetiyle görüntülenir.

scientific

  • Scientific formatlama, ondalıklı sayıları bilimsel (scientific) notasyonda gösterir. Sayı, üstel formda (e veya E) ve belirli bir ondalık hassasiyetle temsil edilir.

hexfloat

  • Hexfloat formatlama, ondalıklı sayıları hexadecimal (onaltılık) biçimde gösterir. Hexadecimal gösterimde, hem fixed hem de scientific ayarları arka planda etkinleştirilmiştir, bu da sayıyı onaltılık bilimsel notasyon ile temsil eder (örneğin, 0x1.3p+4 gibi).

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


ree

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      |
*****************************

ree

 
 
 

Recent Posts

See All
C++ Dilinde [[nodiscard]] attribute

C++’ta [[attribute]] (öznitelik) mekanizması, kod hakkında ek bilgi sağlayarak derleyicinin uyarılar vermesine, belirli optimizasyonlar...

 
 
 
C++ Dilinde constinit

C++20'de tanıtılan önemli bir özellik `constinit`'dir; bu özellik, statik depolama süresine sahip değişkenlerin derleme zamanında...

 
 
 

Comentários


bottom of page