Pemahaman saya adalah bahwa string
adalah anggota dari std
namespace, jadi mengapa tidak 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 dijalankan, myString
cetakan yang tampaknya string acak dari 3 karakter, seperti di output di atas.
It's kompilasi karena printf
isn't tipe aman, karena menggunakan variabel argumen di C akal1. printf
tidak memiliki pilihan untuk std::string
, hanya C-gaya string. Menggunakan sesuatu yang lain di tempat apa yang diharapkan pasti menang't memberikan anda hasil yang anda inginkan. It's benar-benar perilaku tidak terdefinisi, jadi apa pun bisa terjadi.
Cara termudah untuk memperbaiki hal ini, karena anda're menggunakan C++, adalah pencetakan biasanya dengan std::cout
, karena std::string
mendukung bahwa melalui operator overloading:
std::cout << "Follow this command: " << myString;
Jika, untuk beberapa alasan, anda perlu untuk mengambil gaya C string, anda dapat menggunakan c_str()
metode std::string
untuk mendapatkan const char *
yang null-terminated. Menggunakan contoh anda:
#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;
}
Jika anda ingin fungsi yang lebih suka printf
, tapi jenis yang aman, melihat ke variadic template (C++11, didukung pada semua utama penyusun sebagai MSVC12). Anda dapat menemukan contoh dari satu here. Ada's tidak ada yang saya tahu diimplementasikan seperti yang di perpustakaan standar, tapi mungkin ada di Boost, khususnya boost::format
.
[1]: Ini berarti bahwa anda dapat melewati sejumlah argumen, tetapi fungsi bergantung pada anda untuk memberitahu jumlah dan tipe argumen-argumen itu. Dalam kasus printf
, yang berarti string dengan dikodekan jenis informasi seperti %d
yang berarti int
. Jika anda berbohong tentang jenis atau jumlah, fungsi tidak memiliki standar cara untuk mengetahui, meskipun beberapa compiler memiliki kemampuan untuk memeriksa dan memberikan peringatan ketika anda berbaring.
Silakan don't menggunakan printf("%s", your_string.c_str());
Gunakan cout << your_string;
sebagai gantinya. Pendek, sederhana dan typesafe. Pada kenyataannya, ketika anda're penulisan C++, biasanya anda ingin menghindari printf
seluruhnya-it's sisa dari C yang's jarang diperlukan atau berguna dalam C++.
Untuk mengapa anda harus menggunakan cout
bukan printf
, alasan yang lain. Berikut ini's sampling dari beberapa yang paling jelas:
printf
isn't type-safe. Jika jenis anda melewati berbeda dari yang diberikan dalam konversi penspesifikasi, printf
akan mencoba untuk menggunakan apa pun yang ditemukannya di tumpukan seolah-olah itu adalah jenis tertentu, memberikan terdefinisi perilaku. Beberapa kompiler dapat memperingatkan tentang hal ini dalam beberapa keadaan, tetapi beberapa kompiler dapat't/tidak't pada semua, dan tidak dapat di bawah semua keadaan.printf
isn't extensible. Anda hanya dapat melewati tipe primitif itu. Set conversion specifier memahami keras-kode dalam pelaksanaannya, dan ada's tidak ada cara bagi anda untuk menambahkan lebih banyak/lain-lain. Sebagian besar ditulis dengan C++ harus menggunakan jenis ini terutama untuk melaksanakan jenis berorientasi pada masalah yang sedang dipecahkan.cout
memiliki yang menutupi juga. Misalnya:std::lokal loc(""); std::cout.mengilhami(loc);
std::cout << 123456.78;
Nama lokal ("") picks lokal didasarkan pada pengguna's konfigurasi. Oleh karena itu, pada mesin saya (dikonfigurasi untuk bahasa inggris) ini mencetak sebagai 123,456.78
. Untuk seseorang yang memiliki komputer mereka dikonfigurasi untuk (katakanlah) Jerman, itu akan mencetak sesuatu seperti 123.456,78
. Untuk seseorang yang dikonfigurasi untuk India, itu akan mencetak sebagai 1,23,456.78
(dan tentu saja ada banyak orang lain). Dengan printf
saya mendapatkan tepat satu hasilnya: 123456.78
. Hal ini konsisten, tetapi itu's secara konsisten salah untuk semua orang di mana-mana. Pada dasarnya satu-satunya cara untuk mengatasi ini adalah dengan melakukan format secara terpisah, kemudian menyampaikan hasilnya sebagai string untuk printf
, karena printf
itu sendiri hanya akan tidak melakukan pekerjaan dengan benar.
4. Meskipun mereka're cukup kompak, printf
format string dapat cukup terbaca. Bahkan di antara C programmer yang menggunakan printf
hampir setiap hari, saya'd tebak setidaknya 99% akan perlu untuk melihat hal-hal untuk memastikan apa #
di %#x
berarti, dan cara yang berbeda dari apa #
di %#f
berarti (dan ya, mereka berarti hal yang sama sekali berbeda).
gunakan myString.c_str()
jika anda ingin c-seperti string (const char*
) untuk digunakan dengan printf
terima kasih
Printf sebenarnya cukup baik untuk digunakan jika ukuran itu penting. Artinya jika anda menjalankan sebuah program di mana memori merupakan masalah, maka printf sebenarnya sangat baik dan di bawah rater solusi. Cout dasarnya pergeseran bit di atas untuk membuat ruang untuk string, sedangkan printf hanya berlangsung dalam beberapa jenis parameter dan mencetaknya ke layar. Jika anda adalah untuk mengkompilasi sederhana hello world program printf akan mampu menyusun itu dalam waktu kurang dari 60, 000 bit sebagai lawan cout, itu akan mengambil lebih dari 1 juta bit untuk mengkompilasi.
Untuk situasi anda, id sarankan menggunakan cout hanya karena hal ini jauh lebih nyaman untuk digunakan. Meskipun, saya berpendapat bahwa printf adalah sesuatu yang baik untuk tahu.
Alasan utama mungkin adalah bahwa C++ string adalah sebuah struct yang termasuk saat ini-suhu udara turun nilai, bukan hanya alamat urut-urutan dari karakter yang diakhiri dengan 0 byte. Printf dan kerabat berharap untuk menemukan urutan seperti itu, tidak struct, dan oleh karena itu bingung dengan C++ string.
Berbicara untuk diri saya sendiri, saya percaya bahwa printf memiliki tempat yang dapat't dengan mudah diisi oleh C++ fitur sintaksis, seperti struktur tabel dalam html memiliki tempat yang dapat't dengan mudah diisi oleh div. Sebagai Dykstra kemudian menulis tentang goto, dia didn't berniat untuk memulai sebuah agama dan itu benar-benar hanya berdebat melawan menggunakannya sebagai kludge untuk menebus buruk dirancang kode.
Itu akan cukup bagus jika proyek GNU akan menambah printf keluarga mereka g++ ekstensi.
printf
menerima sejumlah variabel argumen. Mereka hanya dapat memiliki Plain Old Data (POD) jenis. Kode yang melewati sesuatu yang lain dari POD printf
hanya mengkompilasi karena compiler mengasumsikan anda punya format yang tepat. %s
berarti bahwa masing-masing argumen ini seharusnya menjadi pointer ke char
. Dalam kasus anda itu adalah std::string
tidak const char*
. printf
tidak tahu itu karena argumen tipe pergi hilang dan seharusnya dikembalikan dari format parameter. Ketika balik yang std::string
argumen ke const char*
yang dihasilkan pointer akan menunjuk ke beberapa yang tidak relevan wilayah dari memori bukan yang anda inginkan C string. Untuk alasan bahwa kode anda mencetak omong kosong.
Sementara printf
adalah pilihan istimewa untuk mencetak teks yang diformat, (terutama jika anda berniat untuk memiliki padding), hal ini dapat berbahaya jika anda belum't diaktifkan compiler peringatan. Selalu mengaktifkan peringatan karena kesalahan-kesalahan seperti ini sebenarnya dapat dengan mudah dihindari. Tidak ada alasan untuk menggunakan kikuk std::cout
mekanisme jika printf
keluarga dapat melakukan tugas yang sama dalam waktu yang jauh lebih cepat dan lebih cantik cara. Pastikan anda telah mengaktifkan semua peringatan (-Dinding -Wextra
) dan anda akan baik. Dalam kasus anda menggunakan kustom anda sendiri printf
implementasi anda harus menyatakan dengan __atribut__
mekanisme yang memungkinkan compiler untuk memeriksa format string terhadap parameter yang diberikan.