Comment diviser un littéral de chaîne sur plusieurs lignes en C / Objective-C?


321

J'ai une assez longue requête sqlite:

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";

Comment le diviser en plusieurs lignes pour en faciliter la lecture? Si je fais ce qui suit:

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

Je reçois une erreur.

Existe-t-il un moyen d'écrire des requêtes sur plusieurs lignes?

Réponses:


569

Il existe deux façons de fractionner des chaînes sur plusieurs lignes:

En utilisant \

Toutes les lignes en C peuvent être divisées en plusieurs lignes à l'aide de \.

Plaine C:

char *my_string = "Line 1 \
                   Line 2";

Objectif c:

NSString *my_string = @"Line1 \
                        Line2";

Meilleure approche

Il existe une meilleure approche qui fonctionne uniquement pour les chaînes.

Plaine C:

char *my_string = "Line 1 "
                  "Line 2";

Objectif c:

NSString *my_string = @"Line1 "
                       "Line2";    // the second @ is optional

La deuxième approche est meilleure, car il n'y a pas beaucoup d'espace blanc inclus. Cependant, pour une requête SQL, les deux sont possibles.

REMARQUE: avec un #define, vous devez ajouter un «\» supplémentaire pour concaténer les deux chaînes:

Plaine C:

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

22
Les deux sont les mêmes que dans et C et C ++. Cette dernière solution est préférée car l'ancienne incorpore beaucoup d'espace blanc inutile dans le programme qui sera également transmis au serveur DB.
Alnitak

Vous manquez un @ au début de la ligne 2 dans le meilleur exemple Objective-C.
Lawrence Johnston

Avez-vous un lien vers une spécification documentant le caractère facultatif de la seconde @?
Heath Borders

@HeathBorders: Pas ici, mais je l'ai recherché quand j'ai écrit la réponse.
Georg Schölly

10
Un autre avantage de la meilleure approche est que vous pouvez mettre // des commentaires après chaque ligne.
fishinear

110

Il y a une astuce que vous pouvez faire avec le pré-processeur.
Il présente les inconvénients potentiels de l'effondrement de l'espace blanc et pourrait être déroutant pour les personnes lisant le code.
Mais, il a l'avantage que vous n'avez pas besoin d'échapper aux guillemets à l'intérieur.

#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
);

le préprocesseur transforme cela en:

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

J'ai utilisé cette astuce lorsque j'écrivais des tests unitaires contenant de grandes chaînes littérales contenant JSON. Cela signifiait que je n'avais pas à échapper à chaque caractère de citation \ ".


5
Parfait! Maintenant, j'ai juste besoin de donner quelques centaines de votes positifs supplémentaires, et de l'amener là où il appartient ...
Mike

Je réagissais de la même manière, mais ce n'est pas sans problème. J'ai juste essayé de faire un hérédoc de cette façon avec un caractère Unicode spécial et j'ai eu une erreur sur les caractères non ASCII non autorisés en dehors des littéraux.
philipkd

+1 mais pour mémoire, j'ai des problèmes avec le compilateur (MSVC) ou l'éditeur (QtCreator) qui ne (re) compile pas l'expression comme il se doit en cas de changement. C'est comme si le changement n'était pas détecté ... Frapper Rebuild au lieu de Build fait l'affaire.
Andreas

Merci pour cette pépite de poulet d'information. Il fait exactement ce que je devais faire sans tous les déchets supplémentaires.
FishGuy876

Cela ne fonctionne malheureusement pas si vous avez des guillemets littéraux dans la chaîne. Eh bien, cela fonctionne en quelque sorte, car il génère un avertissement. Mais ma base de code est -Werror ...
AnilRedshift

24

Vous pouvez également aller dans XCode -> Préférences, sélectionner l'onglet Retrait et activer le retour à la ligne.

De cette façon, vous n'aurez rien à taper de plus, et cela fonctionnera pour les choses que vous avez déjà écrites. :-)

Une chose ennuyeuse est cependant ...

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
}

2
@YoYoYonnY Je suis d'accord, mais je l'apprécie également. Il me semble que ce commentaire n'aurait pas été vraiment possible en tant que commentaire, d'où l'utilisation du format de réponse. Cela semble être une limitation de S / O, que vous ne pouvez pas écrire de commentaires particulièrement riches (pour autant que je sache).
Max von Hippel

24

J'ai ce problème tout le temps, j'ai donc créé un petit outil pour convertir le texte en une chaîne Objective-C multi-lignes échappée:

http://multilineobjc.herokuapp.com/

J'espère que cela vous fera gagner du temps.


1
excellent outil! question: pourquoi échappez-vous à "|"?
justadreamer

Bon point. Je l'ai changé pour ne plus échapper à "|". Merci de me le faire savoir.
Flaviu

J'ai eu la même idée. J'aurais aimé voir ça en premier. Mon outil est: nsstringify.nateflink.com
Nate Flink

1
Merci, ça m'a fait gagner beaucoup de temps!
djskinner

Essayez d'utiliser le format Clang (s'intègre à vos éditeurs préférés): clang.llvm.org/docs/ClangFormat.html
Ahmed Fasih

18

Extension de l' idée de devis pour Objective-C:

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

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

3
#define NSStringMultiline(...) @#__VA_ARGS__devrait aussi fonctionner.
Nicholas Daley

Pour les cordes mutables: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky

Pour moi, la chaîne résultante n'a pas de nouvelles lignes.
rimsky

Les retours à la ligne échappés sont capturés correctement (ce qui n'est pas si pratique ou agréable).
rimsky

@rimsky, et je pense que cela #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]fonctionne également pour les chaînes mutables.
Iulian Onofrei

5

Une autre solution pour la pile, changez votre fichier .m en .mm pour qu'il devienne Objective-C ++ et utilisez des littéraux bruts C ++, comme ceci:

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

Les littéraux bruts ignorent tout jusqu'à la séquence de terminaison, qui dans le cas par défaut est la citation entre parenthèses.

Si la séquence entre guillemets parenthèses doit apparaître quelque part dans la chaîne, vous pouvez également spécifier facilement un délimiteur personnalisé, comme ceci:

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";

J'ai également constaté que GCC ajoute des littéraux de chaîne brute C ++ en tant qu'extension au langage C: stackoverflow.com/questions/797318/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

3

Vous pouvez également faire:

NSString * query = @"SELECT * FROM foo "
                   @"WHERE "
                     @"bar = 42 "
                     @"AND baz = datetime() "
                   @"ORDER BY fizbit ASC";

2

GCC ajoute des littéraux de chaîne brute multilignes C ++ en tant qu'extension C

C ++ 11 a des littéraux de chaîne bruts comme mentionné sur: https://stackoverflow.com/a/44337236/895245

Cependant, GCC les ajoute également en tant qu'extension C, il vous suffit de les utiliser à la -std=gnu99place de -std=c99. Par exemple:

principal c

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

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

Compiler et exécuter:

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

Cela peut être utilisé par exemple pour insérer un assemblage en ligne multiligne dans du code C: Comment écrire du code d'assemblage en ligne multiligne dans GCC C ++?

Il ne vous reste plus qu'à vous détendre et à attendre qu'il soit normalisé sur C20XY.

C ++ a été demandé à: C ++ multiline string literal

Testé sur Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.


0

Une alternative consiste à utiliser n'importe quel outil pour supprimer les sauts de ligne. Écrivez votre chaîne en utilisant n'importe quel éditeur de texte, une fois que vous avez terminé, collez votre texte ici et copiez-le à nouveau dans xcode.


1
Pas vraiment une solution à long terme. Et si vous deviez le changer à nouveau plus tard. Get est agaçant rapidement, mieux vaut utiliser les technologies multi-lignes déjà mentionnées et les formater directement dans le fichier.
Schwarzie2478
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.