Как разбить строковый литерал на несколько строк в C / Objective-C?


321

У меня довольно длинный SQL-запрос:

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

Как я могу разбить его на несколько строк, чтобы было легче читать? Если я сделаю следующее:

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

Я получаю ошибку.

Есть ли способ писать запросы в несколько строк?

Ответы:


569

Есть два способа разбить строки на несколько строк:

С помощью \

Все строки в C могут быть разбиты на несколько строк с помощью \.

Обычный C:

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

Objective-C:

NSString *my_string = @"Line1 \
                        Line2";

Лучший подход

Есть лучший подход, который работает только для строк.

Обычный C:

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

Objective-C:

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

Второй подход лучше, потому что там не так много пробелов. Однако для SQL-запроса возможны оба варианта.

ПРИМЕЧАНИЕ. С помощью #define вы должны добавить дополнительный '\' для объединения двух строк:

Обычный C:

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

22
Оба они такие же, как в C и C ++. Последнее решение является предпочтительным, поскольку первое встраивает много бесполезных пробелов в программу, которые также будут передаваться на сервер БД.
— Альнитак,

Вы пропускаете @ в начале строки 2 в лучшем примере Objective-C.
— Лоуренс Джонстон

У вас есть ссылка на спецификацию, документирующую возможность второго @?
— Хит Границы

@HeathBorders: Не прямо здесь, но я посмотрел, когда написал ответ.
— Георг Шолли

10
Еще одним преимуществом лучшего подхода является то, что вы можете поместить // комментарии после каждой строки.
— fishinear

110

Есть хитрость, которую вы можете сделать с препроцессором.
У него есть потенциальные отрицательные стороны, что он разрушит пробелы, и это может ввести в заблуждение людей, читающих код.
Но есть и обратная сторона: вам не нужно экранировать кавычки внутри.

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

препроцессор превращает это в:

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

Я использовал этот трюк, когда писал некоторые модульные тесты, в которых были большие литеральные строки, содержащие JSON. Это означало, что мне не нужно было избегать каждого символа кавычки \ ".


5
Отлично! Теперь мне просто нужно дать этому еще несколько сотен голосов и получить его там, где он есть ...
— Майк

Я реагировал так же, но это не без проблем. Я просто попытался сделать heredoc таким образом со специальным символом Unicode и получил ошибку о том, что не-ASCII символы не допускаются за пределами литералов.
— philipkd

+1, но для записи, у меня проблемы с компилятором (MSVC) или редактором (QtCreator), который не (пере) компилирует выражение, как это должно быть при изменении. Это как изменение не обнаружено ... Удар Rebuild вместо Build делает свое дело.
— Андреас

Спасибо за этот Куриный Самородок информации. Это делает именно то, что мне нужно было сделать без всего лишнего мусора.
— FishGuy876

К сожалению, это не работает, если в строке есть буквальные кавычки. Ну, это отчасти работает, потому что выдает предупреждение. Но моя кодовая база -Werror ...
— AnilRedshift

24

Вы также можете перейти в XCode -> «Настройки», выбрать вкладку «Отступы» и включить перенос строк.

Таким образом, вам не нужно будет ничего вводить, и это сработает для того, что вы уже написали. :-)

Одна неприятная вещь, хотя ...

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 Я согласен, но я также ценю это. Меня поражает, что этот комментарий не был бы по-настоящему возможен в качестве комментария, отсюда и использование формата ответа. Это похоже на ограничение S / O, что вы не можете писать особенно насыщенные комментарии (насколько я знаю).
— Макс фон Хиппель

24

У меня постоянно возникает эта проблема, поэтому я создал крошечный инструмент для преобразования текста в экранированную многострочную строку Objective-C:

http://multilineobjc.herokuapp.com/

Надеюсь, это сэкономит вам время.


1
отличный инструмент! вопрос: почему вы избегаете '|'?
— justadreamer

Хорошая точка зрения. Я изменил его, чтобы больше не выходить "|". Спасибо, что дал мне знать.
— Флавиу

У меня была такая же идея. Хотел бы я увидеть это первым. Мой инструмент: nsstringify.nateflink.com
— Нейт Флинк,

1
Спасибо, сэкономил мне много времени!
— djskinner

Попробуйте использовать формат Clang (интегрируется с вашими любимыми редакторами): clang.llvm.org/docs/ClangFormat.html
— Ахмед Фасих,

18

Расширение ЦЕНЫ идеи для 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__должно работать тоже.
— Николас Дейли

Для изменяемых струн: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
— Римский

Для меня полученная строка не имеет новых строк.
— Римский

Экранированные символы новой строки перехвачены правильно (что не так удобно или приятно).
— Римский

@rimsky, и я думаю, что это #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]также работает для изменяемых строк.
— Юлиан Онофрей

5

Еще одно решение для кучи, измените ваш файл .m на .mm, чтобы он стал Objective-C ++, и использовали литералы C ++, например:

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

Необработанные литералы игнорируют все до последовательности завершения, которая в случае по умолчанию является кавычкой.

Если последовательность скобок-кавычек должна где-то появиться в строке, вы также можете легко указать собственный разделитель, например так:

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

Я также обнаружил, что GCC добавляет необработанные строковые литералы C ++ в качестве расширения языка C: stackoverflow.com/questions/797318/…
— Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

3

Вы также можете сделать:

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

2

GCC добавляет C ++ многострочные необработанные строковые литералы в качестве расширения C

В C ++ 11 есть необработанные строковые литералы, как указано на: https://stackoverflow.com/a/44337236/895245

Тем не менее, GCC также добавляет их как расширение C, вы просто должны использовать -std=gnu99вместо -std=c99. Например:

main.c

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

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

Скомпилируйте и запустите:

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

Это может быть использовано, например, для вставки многострочной встроенной сборки в код C: Как написать код многострочной встроенной сборки в GCC C ++?

Теперь нужно просто откинуться на спинку кресла и ждать, пока он будет стандартизирован на C20XY.

C ++ спросили по адресу: C ++ многострочный строковый литерал

Протестировано на Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.


0

Альтернативой является использование любого инструмента для удаления разрывов строк. Напишите вашу строку с помощью любого текстового редактора, как только вы закончите, вставьте свой текст сюда и скопируйте его снова в xcode.


1
Нет действительно долгосрочного решения. Что делать, если вам придется изменить это позже. Быстро надоедает, лучше использовать уже упомянутые многострочные техники и форматировать их прямо в файле.
— Schwarzie2478
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.