14

最近、微妙な虫に刺されました。

char ** int2str = {
   "zero", // 0
   "one",  // 1
   "two"   // 2
   "three",// 3
   nullptr };

assert( int2str[1] == std::string("one") ); // passes
assert( int2str[2] == std::string("two") ); // fails

あなたが神のようなコードレビュー力を持っているなら、私が,afterを忘れたことに気付くでしょう"two"

そのバグを見つけるためにかなりの努力をした後、なぜ誰かがこの動作を望んでいるのかを尋ねなければなりませんか?

これがマクロ マジックにどのように役立つかはわかりますが、なぜこれが Python のような現代的な言語の「機能」なのですか?

本番コードで文字列リテラルの連結を使用したことがありますか?

4

11 に答える 11

22

確かに、これはコードの見栄えを良くする簡単な方法です。

char *someGlobalString = "very long "
                         "so broken "
                         "onto multiple "
                         "lines";

ただし、一番の理由は型強制のような変な printf フォーマットのためです:

uint64_t num = 5;
printf("Here is a number:  %"PRIX64", what do you think of that?", num);

定義されているものはたくさんあり、型サイズの要件がある場合に役立ちます。このリンクでそれらをすべてチェックしてください。いくつかの例:

PRIo8 PRIoLEAST16 PRIoFAST32 PRIoMAX PRIoPTR
于 2010-03-24T00:12:54.563 に答える
17

これは、プリプロセッサ文字列を文字列と組み合わせることができる優れた機能です。

// Here we define the correct printf modifier for time_t
#ifdef TIME_T_LONG
    #define TIME_T_MOD "l"
#elif defined(TIME_T_LONG_LONG)
    #define TIME_T_MOD "ll"
#else
    #define TIME_T_MOD ""
#endif

// And he we merge the modifier into the rest of our format string
printf("time is %" TIME_T_MOD "u\n", time(0));
于 2010-03-24T00:12:02.413 に答える
5

これが役立つケース:

  • プリプロセッサによって定義されたコンポーネントを含む文字列の生成 (これはおそらく C での最大の使用例であり、非常に頻繁に目にするものです)。
  • 文字列定数を複数行に分割する

前者のより具体的な例を提供するには:

// in version.h
#define MYPROG_NAME "FOO"
#define MYPROG_VERSION "0.1.2"

// in main.c
puts("Welcome to " MYPROG_NAME " version " MYPROG_VERSION ".");
于 2010-03-24T00:11:33.183 に答える
4

いくつかのCおよびC++の回答が表示されますが、この機能の論理的根拠がなぜ、または実際に何であったかについての実際の回答はありませんか? C++ では、これはC99に由来する機能であり、この機能の理論的根拠は、国際標準の理論的根拠 - プログラミング言語 - Cセクションの6.4.5 文字列リテラルに移動することで見つけることができます(強調鉱山):

バックスラッシュと改行の行継続を使用すると、文字列を複数の行にまたがって継続できますが、これには、文字列の継続が次の行の最初の位置から始まる必要があります。より柔軟なレイアウトを許可し、いくつかの前処理の問題 (§6.10.3 を参照) を解決するために、C89 委員会は文字列リテラルの連結を導入しました。2 つの文字列リテラルが連続して貼り付けられ、途中にヌル文字がなく、1 つの結合文字列リテラルが作成されます。この C 言語への追加により、プログラマーは、バックスラッシュと改行のメカニズムを使用せずに文字列リテラルを物理行の末尾を超えて拡張できるようになり、プログラムのインデント スキームが破壊されます。連結はランタイム操作ではなく字句構造であるため、明示的な連結演算子は導入されませんでした。

同じ理由があると思われるPython\ 。これにより、醜い長い文字列リテラルを続ける必要性が減ります。The Python Language Reference のセクション2.4.2 Stringliteral concatenationで 説明されています。

于 2014-02-07T14:12:13.867 に答える
3

他のプログラミング言語についてはわかりませんが、たとえば C# ではこれを行うことはできません (これは良いことだと思います)。私が知る限り、これが C++ で役立つ理由を示す例のほとんどは、文字列の連結に特別な演算子を使用できる場合でも機能します。

string someGlobalString = "very long " +
                          "so broken " +
                          "onto multiple " +
                          "lines"; 

これは快適ではないかもしれませんが、確実に安全です。あなたの動機付けの例では、,要素を分離するか+、文字列を連結するために追加しない限り、コードは無効になります...

于 2010-03-24T00:30:23.177 に答える
3

Python字句解析リファレンスのセクション2.4.2から:

この機能を使用して、必要なバックスラッシュの数を減らしたり、長い文字列を長い行に分割したり、文字列の一部にコメントを追加したりすることもできます

http://docs.python.org/reference/lexical_analysis.html

于 2010-03-24T00:34:03.943 に答える
2

長い文字列リテラルを複数の行に分割できるようにします。

そして、はい、私はそれを製品コードで見ました。

于 2010-03-24T00:11:27.660 に答える
1

論理的根拠について、Shafik Yaghmour の回答を拡張および単純化します。文字列リテラルの連結は、2 つの理由で用語と同様に C で発生しました (したがって、C++ によって継承されました) (参照はANSI C プログラミング言語の根拠からのものです)。

  • 書式設定の場合: 長い文字列リテラルが適切なインデントで複数行にまたがることができるようにする – インデント スキームを破壊する行継続とは対照的に ( 3.1.4 文字列リテラル); と
  • マクロマジックの場合: (文字列化による) マクロによる文字列リテラルの構築を許可する ( 3.8.3.2 # 演算子)。

Cからコピーしたため、現代の言語であるPythonとDに含まれていますが、これらの両方で、バグが発生しやすく(ご指摘のとおり)、不要であるため(連結を使用できるため)、非推奨として提案されています。コンパイル時の評価のための演算子と定数の折りたたみ; 文字列はポインターであるため、C ではこれを行うことができず、それらを追加することはできません)。

互換性が損なわれるため、削除するのは簡単ではありません。また、優先順位に注意する必要があります (演算子の前に字句解析中に暗黙的な連結が発生しますが、これを演算子に置き換えると、優先順位に注意する必要があることを意味します)。したがって、それがまだ存在する理由.

はい、使用済みの製品コードです。Google Python スタイル ガイド:行の長さの指定:

リテラル文字列が 1 行に収まらない場合は、括弧を使用して暗黙的な行結合を行います。

x = ('This will build a very long long '
     'long long long long long long string')

詳細とリファレンスについては、Wikipedia の「<a href="https://en.wikipedia.org/wiki/String_literal_concatenation" rel="nofollow">文字列リテラル連結」を参照してください。

于 2014-07-10T04:00:17.527 に答える
0

この機能の実際の使用法について人々は私の口から言葉を取り出しましたが、これまでのところ、構文の選択を擁護しようとした人は誰もいません。

私が知っている限りでは、結果としてすり抜けることができるタイプミスはおそらく見過ごされていたでしょう。結局のところ、次のようにさらに示されているように、タイプミスに対する堅牢性はデニスの頭の中にはなかったようです。

if (a = b);
{
    printf("%d", a);
}

さらに、文字列リテラルの連結に余分な記号を使用する価値がなかったという見方もあります。結局のところ、2つでできることは他にほとんどなく、そこに記号があると、次のような誘惑に駆られる可能性があります。 Cの組み込み機能のレベルを超えるランタイム文字列連結に使用してみてください。

C構文に基づく一部の最新の高級言語では、タイプミスが発生しやすいため、この表記が破棄されています。ただし、これらの言語には、+(JS、C#)、.(Perl、PHP)、~(D、ただしCの並置構文も保持されています)などの文字列連結の演算子があり、定数畳み込み(とにかくコンパイルされた言語では)は、実行時のパフォーマンスのオーバーヘッドはありません。

于 2011-03-20T14:52:42.730 に答える
0

私は確かにCとC ++の両方を持っています。率直に言って、その有用性と言語がいかに「現代的」であるかとの間にはあまり関係がありません。

于 2010-03-24T00:10:59.467 に答える