Wie teilt man ein String-Literal über mehrere Zeilen in C / Objective-C auf?

Lesezeit: 6 Minuten

Benutzeravatar von Ilya Suzdalnitski
Ilja Susdalnizki

Ich habe eine ziemlich lange SQLite-Abfrage:

const char *sql_query = "SELECT statuses.word_id FROM lang1_words, statuses WHERE statuses.word_id = lang1_words.word_id ORDER BY lang1_words.word ASC";

Wie kann ich es in mehrere Zeilen umbrechen, um es leichter lesbar zu machen? Wenn ich folgendes mache:

const char *sql_query = "SELECT word_id
                        FROM table1, table2
                        WHERE table2.word_id = table1.word_id
                        ORDER BY table1.word ASC";

Ich erhalte eine Fehlermeldung.

Gibt es eine Möglichkeit, Abfragen in mehreren Zeilen zu schreiben?

Benutzeravatar von Georg Schölly
Georg Scholly

Es gibt zwei Möglichkeiten, Zeichenfolgen über mehrere Zeilen aufzuteilen:

  1. Jede Saite auf einer eigenen Zeile. Funktioniert nur mit Strings:

    • Ebene C:

      char *my_string = "Line 1 "
                        "Line 2";
      
    • Ziel c:

      NSString *my_string = @"Line1 "
                             "Line2";    // the second @ is optional
      
  2. Verwenden \ – kann für jeden Ausdruck verwendet werden:

    • Ebene C:

      char *my_string = "Line 1 \
                         Line 2";
      
    • Ziel c:

      NSString *my_string = @"Line1 \
                              Line2";
      

Der erste Ansatz ist besser, da nicht viele Leerzeichen enthalten sind. Für eine SQL-Abfrage ist jedoch beides möglich.

HINWEIS: Mit a #definemüssen Sie zusätzlich hinzufügen \ um die beiden Strings zu verketten:

Ebene C:

#define kMyString "Line 1"\
                  "Line 2"

  • Beide sind die gleichen wie in und C und C++. Die letztere Lösung wird bevorzugt, weil erstere a einbettet viel von nutzlosem Leerraum in das Programm, der ebenfalls an den DB-Server übertragen wird.

    – Alnitak

    28. April 2009 um 11:34 Uhr

  • Im besseren Objective-C-Beispiel fehlt ein @ am Anfang von Zeile 2.

    – Rotholz

    15. Juni 2010 um 23:27 Uhr

  • Haben Sie einen Link zu einer Spezifikation, die die Optionalität der zweiten dokumentiert? @?

    – Heidegrenzen

    5. Juni 2012 um 18:10 Uhr

  • Ein weiterer Vorteil des besseren Ansatzes ist, dass Sie nach jeder Zeile // Kommentare einfügen können.

    – fischnah

    2. Dezember 2013 um 13:37 Uhr

  • Funktioniert der zweite Ansatz auch nicht \n oder \r\n zwischen den Zeilen?

    – Karl W

    14. August 2017 um 23:09 Uhr

Es gibt einen Trick, den Sie mit dem Präprozessor machen können.
Es hat die potenziellen Nachteile, dass es den Leerraum zusammenbrechen lässt, und könnte für Leute, die den Code lesen, verwirrend sein.
Aber es hat den Vorteil, dass Sie keine Anführungszeichen darin maskieren müssen.

#define QUOTE(...) #__VA_ARGS__
const char *sql_query = QUOTE(
    SELECT word_id
    FROM table1, table2
    WHERE table2.word_id = table1.word_id
    ORDER BY table1.word ASC
);

Der Präprozessor verwandelt dies in:

const char *sql_query = "SELECT word_id FROM table1, table2 WHERE table2.word_id = table1.word_id ORDER BY table1.word ASC";

Ich habe diesen Trick verwendet, als ich einige Komponententests geschrieben habe, die große Literalzeichenfolgen mit JSON enthielten. Das bedeutete, dass ich nicht jedem Anführungszeichen \” entkommen musste.

  • Perfekt! Jetzt muss ich dem nur noch ein paar hundert positive Stimmen geben und es dahin bringen, wo es hingehört …

    – Mike

    22. Oktober 2014 um 12:29 Uhr

  • Ich habe genauso reagiert, aber das ist nicht ohne Probleme. Ich habe gerade versucht, auf diese Weise ein Heredoc mit einem speziellen Unicode-Zeichen zu erstellen, und habe eine Fehlermeldung erhalten, dass Nicht-ASCII-Zeichen außerhalb von Literalen nicht zulässig sind.

    – Philippd

    4. Januar 2017 um 13:42 Uhr

  • +1, aber fürs Protokoll: Ich habe Probleme mit dem Compiler (MSVC) oder dem Editor (QtCreator), der den Ausdruck bei einer Änderung nicht (neu) kompiliert. Es ist, als ob Änderungen nicht erkannt werden … Das Drücken von Rebuild anstelle von Build reicht aus.

    –Andreas

    11. Oktober 2017 um 18:57 Uhr


  • Vielen Dank für dieses Chicken Nugget an Informationen. Es macht genau das, was ich tun musste, ohne den ganzen zusätzlichen Müll.

    – FishGuy876

    23. August 2019 um 13:55 Uhr

  • Dies funktioniert leider nicht, wenn Sie wörtliche Anführungszeichen in der Zeichenfolge haben. Nun, es funktioniert irgendwie, indem es eine Warnung generiert. Aber meine Codebasis ist -Werror …

    – AnilRedshift

    30. Mai 2020 um 3:11 Uhr

Sie können auch zu XCode -> Einstellungen gehen, die Registerkarte Einzug auswählen und Zeilenumbruch aktivieren.

Auf diese Weise müssen Sie nichts extra eingeben und es funktioniert für das, was Sie bereits geschrieben haben. 🙂

Eine ärgerliche Sache ist jedoch …

if (you're long on indentation
    && short on windows) {
            then your code will
                end up squished
                     against th
                         e side
                             li
                              k
                              e

                              t
                              h
                              i
                              s
}

  • @YoYoYonnY Ich stimme zu, aber ich weiß es auch zu schätzen. Mir fällt auf, dass dieser Kommentar als Kommentar nicht wirklich möglich gewesen wäre, daher die Verwendung des Antwortformats. Dies scheint eine Einschränkung von S / O zu sein, dass Sie keine besonders ausführlichen Kommentare schreiben können (soweit ich weiß).

    – Max von Hippel

    27. September 2016 um 11:01 Uhr

Ich habe dieses Problem die ganze Zeit, also habe ich ein kleines Tool erstellt, um Text in einen mehrzeiligen Objective-C-String mit Escapezeichen zu konvertieren:

http://multilineobjc.herokuapp.com/

Ich hoffe, das spart Ihnen etwas Zeit.

Benutzeravatar von Berik
Berik

Erweiterung der Quote-Idee für Objective-C:

#define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]

NSString *sql = NSStringMultiline(
    SELECT name, age
    FROM users
    WHERE loggedin = true
);

  • #define NSStringMultiline(...) @#__VA_ARGS__ sollte auch funktionieren.

    – Nicholas Daley-Okoye

    31. Januar 2015 um 3:41 Uhr

  • Für veränderliche Zeichenfolgen: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]

    – Rimsky

    21. März 2015 um 0:40 Uhr


  • Für mich hat die resultierende Zeichenfolge keine neuen Zeilen.

    – Rimsky

    21. März 2015 um 0:45 Uhr

  • Escape-Zeilenumbrüche werden korrekt erfasst (was bei weitem nicht so praktisch oder schön ist).

    – Rimsky

    21. März 2015 um 0:52 Uhr

  • @rimsky, und ich denke das #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy] funktioniert auch für veränderliche Saiten.

    – Julian Onofrei

    17. Februar 2016 um 8:57 Uhr

Eine weitere Lösung für den Stapel: Ändern Sie Ihre .m-Datei in .mm, sodass sie zu Objective-C++ wird, und verwenden Sie C++-Rohliterale wie folgt:

const char *sql_query = R"(SELECT word_id
                           FROM table1, table2
                           WHERE table2.word_id = table1.word_id
                           ORDER BY table1.word ASC)";

Raw-Literale ignorieren alles bis zur Beendigungssequenz, die im Standardfall Klammer-Anführungszeichen ist.

Wenn die Klammer-Anführungszeichen-Sequenz irgendwo in der Zeichenfolge erscheinen muss, können Sie auch einfach ein benutzerdefiniertes Trennzeichen wie folgt angeben:

const char *sql_query = R"T3RM!N8(
                                  SELECT word_id
                                  FROM table1, table2
                                  WHERE table2.word_id = table1.word_id
                                  ORDER BY table1.word ASC
                         )T3RM!N8";

  • #define NSStringMultiline(...) @#__VA_ARGS__ sollte auch funktionieren.

    – Nicholas Daley-Okoye

    31. Januar 2015 um 3:41 Uhr

  • Für veränderliche Zeichenfolgen: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]

    – Rimsky

    21. März 2015 um 0:40 Uhr


  • Für mich hat die resultierende Zeichenfolge keine neuen Zeilen.

    – Rimsky

    21. März 2015 um 0:45 Uhr

  • Escape-Zeilenumbrüche werden korrekt erfasst (was bei weitem nicht so praktisch oder schön ist).

    – Rimsky

    21. März 2015 um 0:52 Uhr

  • @rimsky, und ich denke das #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy] funktioniert auch für veränderliche Saiten.

    – Julian Onofrei

    17. Februar 2016 um 8:57 Uhr

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

GCC fügt mehrzeilige unformatierte C++-String-Literale als C-Erweiterung hinzu

C++11 hat rohe Zeichenfolgenliterale, wie unter: https://stackoverflow.com/a/44337236/895245 erwähnt

GCC fügt sie jedoch auch als C-Erweiterung hinzu, Sie müssen sie nur verwenden -std=gnu99 Anstatt von -std=c99. Z.B:

Haupt c

#include <assert.h>
#include <string.h>

int main(void) {
    assert(strcmp(R"(
a
b
)", "\na\nb\n") == 0);
}

Kompilieren und ausführen:

gcc -o main -pedantic -std=gnu99 -Wall -Wextra main.c
./main

Dies kann zum Beispiel verwendet werden, um mehrzeilige Inline-Assembly in C-Code einzufügen: Wie schreibt man mehrzeiligen Inline-Assembly-Code in GCC C++?

Jetzt müssen Sie sich nur noch zurücklehnen und darauf warten, dass es auf C20XY standardisiert wird.

C++ wurde gefragt bei: C++ Multiline String Literal

Getestet auf Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.

1427470cookie-checkWie teilt man ein String-Literal über mehrere Zeilen in C / Objective-C auf?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy