string
はstd
名前空間のメンバーであると私は理解しています。では、なぜ次のようになるのでしょうか。
#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;
}
プログラムが実行されるたびに、myString
は、上の出力のように、一見ランダムな3文字の文字列を出力します。
printf
はCの意味で可変引数を使用するため、タイプセーフではないため、コンパイル中です。1。 printf
にはstd::string
のオプションはなく、Cスタイルの文字列のみがあります。それが期待するものの代わりに他のものを使用することは間違いなくあなたにあなたが望む結果を与えません。実際には未定義の動作であるため、何でも起こります。
これを修正する最も簡単な方法は、C++を使用しているため、通常std::cout
で印刷することです。これは、std::string
が演算子のオーバーロードを通じてサポートしているためです。
std::cout << "Follow this command: " << myString;
何らかの理由でCスタイルの文字列を抽出する必要がある場合は、std::string
のc_str()
メソッドを使用して、NULLで終了するconst char *
を取得できます。あなたの例を使用して:
#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;
}
printf
に似ているがタイプセーフな関数が必要な場合は、変数テンプレート(C++ 11、MSVC12以降のすべての主要なコンパイラでサポート)を調べてください。 here の例があります。標準ライブラリにそのように実装されていることは私が知っていることはありませんが、Boost、特に boost::format
にあるかもしれません。
[1]:これは、任意の数の引数を渡すことができることを意味しますが、関数は、それらの引数の数とタイプを伝えるためにあなたに依存しています。 printf
の場合、%d
のようなエンコードされた型情報を持つ文字列はint
を意味します。型や数値についてうそをつくと、関数には標準的な認識方法がありませんが、一部のコンパイラーはうそをつくときにチェックして警告を出すことができます。
printf("%s", your_string.c_str());
を使わないでください
代わりにcout << your_string;
を使用してください。短く、シンプルでタイプセーフです。実際、あなたがC++を書いているとき、あなたは一般的にprintf
を完全に避けたい - それはC++でめったに必要とされないか、または役に立つCからの残り物です。
なぜに関してはcout
の代わりにprintf
を使うべきですが、その理由は数多くあります。これは、最も明白ないくつかのサンプルです。
printf
はタイプセーフではありません。渡された型が変換指定子で指定された型と異なる場合、printf
は、スタック上で見つかったものが指定された型であるかのように使用しようとし、未定義の動作をします。状況によってはこれについて警告できるコンパイラもありますが、まったくできない、またはまったくできないコンパイラもあります。すべての状況下ではできないコンパイラもあります。printf
は拡張できません。あなたはそれにだけプリミティブ型を渡すことができます。それが理解する変換指定子のセットはその実装でハードコードされています、そしてあなたがもっと/他を追加する方法はありません。最もよく書かれたC++はこれらの型を主に解決される問題に向けられた型を実装するために使うべきです。それはまともなフォーマットをはるかに困難にします。明らかな例として、読む人のために数字を印刷するときは、通常、数桁ごとに数千の区切り記号を挿入します。正確な桁数と区切り文字として使用される文字はさまざまですが、cout
にも含まれています。例えば:
std::locale loc("");
std::cout.imbue(loc);
std::cout << 123456.78;
名前のないロケール( "")は、ユーザーの設定に基づいてロケールを選択します。したがって、私のマシン(アメリカ英語用)では、これは123,456.78
として出力されます。自分のコンピュータがドイツ用に設定されている人にとっては、123.456,78
のようなものが表示されます。インド向けに設定されている人にとっては、1,23,456.78
として印刷されるでしょう(そしてもちろん他にもたくさんあります)。 printf
を使用すると、正確に1つの結果が得られます。123456.78
。それは一貫していますが、どこにいても一貫して間違っています。基本的にこれを回避する唯一の方法は、書式設定を個別に行い、結果を文字列としてprintf
に渡すことです。printf
自体は単純にしません仕事は正しく。
printf
フォーマット文字列は全く読めないことがあります。 printf
を実質的に毎日使用しているCプログラマーの間でも、#
の%#x
が何を意味するのか、そしてそれが#
の%#f
が何を意味するのかを確かめるために少なくとも99%調べなければならないでしょうそれらはまったく異なるものを意味します。printfでcのような文字列(const char *)を使用したい場合は、myString.c_str()を使用してください。
std :: printf およびc_str()の例を使用してください。
std::printf("Follow this command: %s", myString.c_str());
サイズが問題であれば、printfは実際にはかなり使用に適しています。あなたがメモリが問題となっているプログラムを走らせているならば、printfは実際には非常に優れていて評価が十分ではありません。 Coutは文字列のためのスペースを空けるために基本的にビットをシフトしますが、printfはある種のパラメータを取り込んでそれを画面に表示します。単純なhello worldプログラムをコンパイルする場合、printfはcoutとは対照的に60,000ビット未満でコンパイルできます。コンパイルには100万ビット以上かかります。
あなたの状況では、idはcoutの使用をお勧めします。それは単に使用するほうがはるかに便利だからです。しかし、私はprintfが知っておくと良いことだと主張するでしょう。
printf
は、可変個の引数を受け入れます。それらはPlain Old Data(POD)タイプだけを持つことができます。 POD以外のものをprintf
に渡すコードは、ユーザーが正しい形式であると見なすため、コンパイルのみを行います。 %s
は、それぞれの引数がchar
へのポインタであると想定されていることを意味します。あなたの場合それはstd::string
ではなくconst char*
です。引数の型が失われて、formatパラメータから復元されることになっているため、printf
はそれを認識していません。そのstd::string
引数をconst char*
に変えるとき、結果のポインタはあなたの望んだC文字列の代わりに無関係なメモリの領域を指すでしょう。そのため、あなたのコードはちんぷんかんぷんと印刷します。
printf
は フォーマットされたテキスト を印刷するための優れた選択ですが(特にパディングを使用したい場合)、コンパイラの警告を有効にしていないと危険です。 このような間違いは簡単に回避できるため、常に警告を有効にしてください。 printf
ファミリが同じタスクをはるかに速くてきれいに実行できる場合は、不器用なstd::cout
メカニズムを使用する理由はありません。すべての警告(-Wall -Wextra
)が有効になっていることを確認してください。独自のカスタムprintf
実装を使用する場合は、 を指定したパラメーターに対してフォーマット文字列をチェックする ことを可能にする__attribute__
メカニズムを使用して宣言する必要があります。
主な理由はおそらく、C++文字列が0バイトで終了する一連の文字のアドレスだけでなく、現在の長さの値を含む構造体であることです。 Printfとその親戚は、構造体ではなくそのようなシーケンスを見つけることを期待しているので、C++文字列と混同されます。
私自身といえば、htmlのテーブル構造がdivで簡単に埋めることができない場所があるように、printfにはC++構文機能で簡単に埋めることができない場所があると思います。 Dykstraが後藤について後で書いたように、彼は宗教を始めるつもりはなかった、そして実際にはよく設計されていないコードを埋め合わせるための問題としてそれを使用することに対して反対しているだけだった。
GNUプロジェクトがprintfファミリーを彼らのg ++拡張に追加することができれば、それは非常に素晴らしいことです。