инициализировать строку C множеством строк в кавычках - PullRequest
3 голосов
/ 01 декабря 2009

Я думал, что строка C может быть инициализирована одной и только одной строкой в ​​кавычках.Мне просто интересно, как это правильно?

char const help_message [] =   
   "Usage: %s [options] files ...\n"   
   "\n"   
   "Options include:\n"   
   " --verbose -v    Be verbose\n"   
   " --help -h       Print this help message\n"   
   " --output -o     Specify output file\n"     
   "\n" ;   

 printf (help_message, argv [0]) ;

Ответы [ 5 ]

12 голосов
/ 01 декабря 2009

Компилятор автоматически объединит смежные строки.

Это может быть очень полезно для повышения читабельности, как в вашем примере, или с некоторыми функциями препроцессора:

#define LOG(x) printf("%s", "Logging: " x)

LOG("HeyHey");

Довольно надуманный пример, но все понятно.

2 голосов
/ 01 декабря 2009

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

char const help_message[] = "Usage: %s [options] files ...\n\nOptions include:\n --verbose -v    Be verbose\n --help -h       Print this help message\n --output -o     Specify output file\n\n";

Представьте, что вы пытаетесь поддерживать это вместо этого. Кроме того, если вы используете многострочный строковый литерал, вы должны либо экранировать символы новой строки, либо иметь дело с тем, что использует исходный код, который может не быть '\n', и вам придется внимательно следить за отступами. Все это делает код в вашем примере лучше.

Вот пример макроса:

#define STRINGIZE_(v) #v
#define STRINGIZE(v) STRINGIZE_(v)

#define LOCATION __FILE__ ":" STRINGIZE(__LINE__)

#define MY_ASSERT(expr) do { \
   if (!(expr)) \
     some_function(LOCATION ": assertion failed in " \
                   __PRETTY_FUNCTION__ ": " #expr); \
} while (0)

(Есть альтернативы этому, такие как передача отдельных параметров и использование специфичного для GCC __PRETTY_FUNCTION__, например, устарел , но все остальное удобно, и это достойный "реал" пример, имхо.)

Другие проблемы, поднятые в этом коде, чтобы знать:

  • одиночный # - оператор преобразования строки препроцессора (## - другой специальный оператор препроцессора для вставки токена)
  • без второго макроса stringize, вы получите "filename.c:__LINE__"
  • использование do-while не прерывает if-else и требует, чтобы макрос использовался как выражение, а не как выражение
    • предотвращение использования в качестве выражения не всегда полезно, но это то, что вы хотите для макросов типа assert

Пример взлома if-else:

if (cond) MY_ASSERT(blah);
else other();

Расширяется до:

if (cond) do { ... } while(0);
else other();

Вместо:

if (cond) if (...) ...;
else other();

Что неверно и удивительно:

if (cond) {
  if (...) {
    ...;
  }
  else {
    other();
  }
}
2 голосов
/ 01 декабря 2009

Ваш инициализатор содержит только один строковый литерал. То, что выглядит как несколько "" -замкнутых строковых литералов, будет фактически объединено в один строковый литерал на 6-м этапе перевода (после предварительной обработки).

2 голосов
/ 01 декабря 2009

Не путайте с массивом строк:

{"xxx" ,
"yyyy",
"3534"}

То, что вы опубликовали, представляет собой одну строку.

2 голосов
/ 01 декабря 2009

Поскольку компилятор считает, что соседние строки в кавычках считаются частью одной и той же строки. Грамматика С специально позволяет это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...