Pemahaman saya adalah itu string
adalah anggota std
namespace, jadi mengapa hal berikut terjadi?
#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;
}
Setiap kali program berjalan, myString
mencetak string 3 karakter yang tampaknya acak, seperti pada output di atas.
Jawaban:
Mengkompilasi karena
printf
bukan tipe aman, karena menggunakan argumen variabel dalam pengertian C 1 .printf
tidak memiliki opsi untukstd::string
, hanya string gaya-C. Menggunakan sesuatu yang lain di tempat yang diharapkannya pasti tidak akan memberi Anda hasil yang Anda inginkan. Ini sebenarnya perilaku yang tidak terdefinisi, sehingga apa pun bisa terjadi.Cara termudah untuk memperbaikinya, karena Anda menggunakan C ++, adalah mencetaknya dengan normal
std::cout
, karenastd::string
mendukungnya melalui overloading operator:Jika, karena alasan tertentu, Anda perlu mengekstrak string gaya-C, Anda dapat menggunakan
c_str()
metodestd::string
untuk mendapatkanconst char *
yang diakhiri dengan null. Menggunakan contoh Anda:Jika Anda menginginkan fungsi yang seperti
printf
, tetapi mengetikkan safe, lihatlah templat variadic (C ++ 11, yang didukung pada semua kompiler utama pada MSVC12). Anda dapat menemukan contohnya di sini . Tidak ada yang saya tahu tentang implementasi seperti itu di perpustakaan standar, tetapi mungkin ada di Boost, khususnyaboost::format
.[1]: Ini berarti Anda bisa memberikan sejumlah argumen, tetapi fungsinya bergantung pada Anda untuk memberi tahu nomor dan jenis argumen itu. Dalam kasus ini
printf
, itu berarti sebuah string dengan tipe informasi yang dikodekan seperti%d
maknaint
. Jika Anda berbohong tentang jenis atau angka, fungsi tidak memiliki cara standar untuk mengetahui, meskipun beberapa penyusun memiliki kemampuan untuk memeriksa dan memberikan peringatan ketika Anda berbohong.sumber
Tolong jangan gunakan
printf("%s", your_string.c_str());
Gunakan
cout << your_string;
sebagai gantinya. Singkat, sederhana, dan aman untuk mengetik. Bahkan, ketika Anda menulis C ++, Anda umumnya ingin menghindariprintf
sepenuhnya - itu adalah sisa dari C yang jarang dibutuhkan atau berguna dalam C ++.Seperti mengapa Anda harus menggunakan
cout
bukanprintf
, alasan banyak. Berikut beberapa contoh yang paling jelas:printf
tidak aman bagi tipe. Jika jenis yang Anda berikan berbeda dari yang diberikan dalam specifier konversi,printf
akan mencoba menggunakan apa pun yang ditemukan di tumpukan seolah-olah itu jenis yang ditentukan, memberikan perilaku yang tidak ditentukan. Beberapa kompiler dapat memperingatkan tentang hal ini dalam beberapa keadaan, tetapi beberapa kompiler tidak bisa / tidak akan sama sekali, dan tidak ada yang bisa dalam semua keadaan.printf
tidak bisa diperpanjang. Anda hanya dapat meneruskan tipe primitif ke dalamnya. Himpunan penentu konversi yang dipahaminya memiliki kode-keras dalam implementasinya, dan tidak ada cara bagi Anda untuk menambahkan lebih banyak / orang lain. Kebanyakan C ++ yang ditulis dengan baik harus menggunakan tipe-tipe ini terutama untuk mengimplementasikan tipe yang berorientasi pada masalah yang sedang dipecahkan.Itu membuat pemformatan yang layak jauh lebih sulit. Untuk contoh yang jelas, saat Anda mencetak angka untuk dibaca orang, Anda biasanya ingin memasukkan ribuan pemisah setiap beberapa digit. Jumlah pasti digit dan karakter yang digunakan sebagai pemisah bervariasi, tetapi
cout
juga mencakup hal itu. Sebagai contoh:Lokal tanpa nama ("") memilih lokal berdasarkan konfigurasi pengguna. Oleh karena itu, pada mesin saya (dikonfigurasi untuk Bahasa Inggris AS) ini dicetak sebagai
123,456.78
. Untuk seseorang yang memiliki komputer mereka dikonfigurasi untuk (katakanlah) Jerman, itu akan mencetak sesuatu seperti123.456,78
. Untuk seseorang yang dikonfigurasi untuk India, itu akan dicetak sebagai1,23,456.78
(dan tentu saja ada banyak lainnya). Denganprintf
saya mendapatkan tepat satu hasil:123456.78
. Itu konsisten, tetapi konsisten salah untuk semua orang di mana pun. Pada dasarnya satu-satunya cara untuk bekerja di sekitar itu adalah untuk melakukan format secara terpisah, kemudian lulus hasilnya sebagai string untukprintf
, karenaprintf
itu sendiri hanya akan tidak melakukan pekerjaan dengan benar.printf
format string bisa sangat tidak dapat dibaca. Bahkan di antara programmer C yang menggunakanprintf
hampir setiap hari, saya kira setidaknya 99% perlu mencari hal-hal untuk memastikan apa artinya#
di%#x
, dan bagaimana itu berbeda dari apa artinya#
di%#f
(dan ya, mereka berarti hal yang sama sekali berbeda ).sumber
#include <string>
. VC ++ memiliki beberapa keanehan pada tajuknya yang memungkinkan Anda menentukan string, tetapi tidak mengirimkannyacout
, tanpa menyertakan<string>
tajuk.cout
lebih lambat, itu karena Anda telah menggunakanstd::endl
tempat yang tidak seharusnya.gunakan
myString.c_str()
jika Anda ingin string c-like (const char*
) digunakan dengan printfTerima kasih
sumber
Gunakan std :: printf dan c_str () contoh:
sumber
Alasan utama mungkin adalah bahwa string C ++ adalah sebuah struct yang menyertakan nilai panjang-saat ini, bukan hanya alamat urutan karakter yang diakhiri oleh 0 byte. Printf dan kerabatnya berharap menemukan urutan seperti itu, bukan struct, dan karena itu menjadi bingung oleh string C ++.
Berbicara sendiri, saya percaya bahwa printf memiliki tempat yang tidak dapat dengan mudah diisi oleh fitur sintaksis C ++, sama seperti struktur tabel dalam html memiliki tempat yang tidak dapat dengan mudah diisi oleh divs. Ketika Dykstra menulis kemudian tentang goto, dia tidak berniat untuk memulai agama dan benar-benar hanya berdebat menentang menggunakannya sebagai kludge untuk menebus kode yang dirancang dengan buruk.
Akan lebih baik jika proyek GNU akan menambahkan keluarga printf ke ekstensi g ++ mereka.
sumber
Printf sebenarnya cukup bagus untuk digunakan jika ukuran penting. Berarti jika Anda menjalankan program di mana masalah memori, maka printf sebenarnya adalah solusi yang sangat bagus dan di bawah penilai. Pada dasarnya Cout menggeser bit untuk memberi ruang bagi string, sementara printf hanya mengambil semacam parameter dan mencetaknya ke layar. Jika Anda mengkompilasi program hello world yang sederhana, printf akan dapat mengkompilasinya dalam waktu kurang dari 60.000 bit dibandingkan dengan cout, akan membutuhkan lebih dari 1 juta bit untuk dikompilasi.
Untuk situasi Anda, id sarankan menggunakan cout hanya karena jauh lebih nyaman untuk digunakan. Meskipun, saya berpendapat bahwa printf adalah sesuatu yang baik untuk diketahui.
sumber
printf
menerima sejumlah variabel argumen. Mereka hanya dapat memiliki tipe Data Lama Biasa (POD). Kode yang meneruskan apa pun selain PODprintf
hanya mengkompilasi karena kompilator menganggap Anda mendapatkan format yang benar.%s
berarti bahwa argumen masing-masing seharusnya menjadi penunjuk kechar
. Dalam kasus Anda itustd::string
bukanconst char*
.printf
tidak mengetahuinya karena tipe argumen hilang dan seharusnya dikembalikan dari parameter format. Ketika mengubahstd::string
argumen itu menjadiconst char*
pointer yang dihasilkan akan menunjuk ke beberapa wilayah memori yang tidak relevan alih-alih string C yang Anda inginkan. Karena alasan itu, kode Anda mencetak omong kosong.Meskipun
printf
merupakan pilihan yang sangat baik untuk mencetak teks yang diformat , (terutama jika Anda bermaksud memiliki padding), itu bisa berbahaya jika Anda belum mengaktifkan peringatan kompiler. Selalu aktifkan peringatan karena kesalahan seperti ini mudah dihindari. Tidak ada alasan untuk menggunakanstd::cout
mekanisme canggung jikaprintf
keluarga dapat melakukan tugas yang sama dengan cara yang jauh lebih cepat dan lebih cantik. Pastikan Anda telah mengaktifkan semua peringatan (-Wall -Wextra
) dan Anda akan baik-baik saja. Jika Anda menggunakanprintf
implementasi kustom Anda sendiri, Anda harus mendeklarasikannya dengan__attribute__
mekanisme yang memungkinkan kompiler untuk memeriksa string format terhadap parameter yang disediakan .sumber