Anladığım kadarıyla string
std
isim alanının bir üyesi, öyleyse neden aşağıdakiler oluşuyor?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Program her çalıştığında, myString
yukarıdaki çıktıda olduğu gibi 3 karakterden oluşan rastgele bir dize yazdırır.
Derleniyor çünkü printf' C anlamında değişken argümanlar kullandığı için tip güvenli değil<sup>1</sup>. printf
in std::string
için bir seçeneği yoktur, sadece C tarzı bir string kullanır. Beklediği şey yerine başka bir şey kullanmak kesinlikle size istediğiniz sonuçları vermeyecektir. Aslında bu tanımlanmamış bir davranıştır, yani her şey olabilir.
C++ kullandığınız için bunu düzeltmenin en kolay yolu, std::string
operatör aşırı yükleme yoluyla bunu desteklediğinden, std::cout
ile normal olarak yazdırmaktır:
std::cout << "Follow this command: " << myString;
Herhangi bir nedenle C tarzı dizeyi çıkarmanız gerekirse, null-terminated olan bir const char *
elde etmek için std::string
in c_str()
yöntemini kullanabilirsiniz. Örneğinizi kullanarak:
#include <iostream>
#include <string>
#include <stdio.h>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString.c_str()); //note the use of c_str
cin.get();
return 0;
}
Eğer printf
gibi ama tip güvenliği olan bir fonksiyon istiyorsanız, variadic şablonlara bakın (C++11, MSVC12'den itibaren tüm büyük derleyicilerde desteklenmektedir). Bir örneğini [burada] bulabilirsiniz (https://web.archive.org/web/20131018185034/http://www.generic-programming.org/~dgregor/cpp/variadic-templates.html). Standart kütüphanede bu şekilde uygulanmış bildiğim bir şey yok, ancak Boost'ta, özellikle boost::format
olabilir.
[1]: Bu, istediğiniz sayıda argüman aktarabileceğiniz, ancak fonksiyonun bu argümanların sayısını ve türlerini söylemenize bağlı olduğu anlamına gelir. printfdurumunda, bu
intanlamına gelen
%d` gibi kodlanmış tür bilgisine sahip bir dize anlamına gelir. Tür veya sayı hakkında yalan söylerseniz, bazı derleyiciler yalan söylediğinizde kontrol etme ve uyarı verme yeteneğine sahip olsa da, işlevin bunu bilmesinin standart bir yolu yoktur.
Lütfen printf("%s", your_string.c_str());
kullanmayın
Bunun yerine cout << your_string;
kullanın. Kısa, basit ve tip güvenli. Aslında, C++ yazarken, genellikle `printf'den tamamen kaçınmak istersiniz - C++'da nadiren ihtiyaç duyulan veya kullanışlı olan C'den kalma bir kalıntıdır.
Neden printf
yerine cout
kullanmanız gerektiğine gelince, bunun çok sayıda nedeni vardır. İşte en belirgin olanlardan birkaç örnek:
Soruda gösterildiği gibi, printf' tip güvenli değildir. Aktardığınız tür, dönüşüm belirtecinde verilenden farklıysa,
printf` yığında bulduğu her şeyi belirtilen türmüş gibi kullanmaya çalışacak ve tanımsız davranışa neden olacaktır. Bazı derleyiciler bazı durumlarda bu konuda uyarabilir, ancak bazı derleyiciler bunu yapamaz/yapmayacaktır ve hiçbiri her koşulda yapamaz.
printf' genişletilebilir değildir. Ona sadece ilkel tipleri aktarabilirsiniz. Anladığı dönüşüm belirticileri kümesi, uygulamasında sabit kodlanmıştır ve daha fazlasını/diğerlerini eklemenizin bir yolu yoktur. Çoğu iyi yazılmış C++, bu tipleri öncelikle çözülen probleme yönelik tipleri uygulamak için kullanmalıdır.
Düzgün biçimlendirmeyi çok daha zor hale getirir. Açık bir örnek vermek gerekirse, insanların okuması için sayıları yazdırırken, genellikle her birkaç basamakta bir binlik ayırıcı eklemek istersiniz. Tam hane sayısı ve ayırıcı olarak kullanılan karakterler değişir, ancak cout
bunu da kapsar. Örneğin:
std::locale loc("");
std::cout.imbue(loc);
std::cout << 123456.78;
İsimsiz yerel ayar ("") kullanıcının yapılandırmasına göre bir yerel ayar seçer. Bu nedenle, benim makinemde (ABD İngilizcesi için yapılandırılmış) bu 123,456.78
olarak yazdırılır. Bilgisayarı (diyelim ki) Almanya için yapılandırılmış biri için 123.456,78
gibi bir şey yazdıracaktır. Bilgisayarı Hindistan için yapılandırılmış biri için ise 1,23,456.78
olarak yazdırılacaktır (ve tabii ki daha pek çok seçenek vardır). printfile tam olarak tek bir sonuç elde ediyorum:
123456.78. Tutarlı, ancak her yerde herkes için tutarlı bir şekilde *yanlış*. Aslında bunu aşmanın tek yolu, biçimlendirmeyi ayrı olarak yapmak ve ardından sonucu
printfe bir dize olarak aktarmaktır, çünkü
printf`in kendisi işi doğru bir şekilde yapmayacaktır.
Oldukça kompakt olmalarına rağmen, printf
format dizeleri oldukça okunaksız olabilir. Hemen hemen her gün printf
kullanan C programcılarının bile en az %99'unun %#x
içindeki #
'nin ne anlama geldiğinden ve bunun %#f
içindeki #
'den ne kadar farklı olduğundan emin olmak için bir şeylere bakması gerektiğini tahmin ediyorum (ve evet, tamamen farklı şeyler ifade ediyorlar).
printf ile kullanmak için c benzeri bir dize (const char*
) istiyorsanız myString.c_str()
kullanın
Teşekkürler