Зачем разрешать конкатенацию строковых литералов? - PullRequest
11 голосов
/ 24 марта 2010

Меня недавно укусила небольшая ошибка.

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

Если у вас есть божественные полномочия просмотра кода, вы заметите, что я забыл , после "two".

Послезначительные усилия, чтобы найти эту ошибку, которую я должен спросить зачем кому-то хотеть такое поведение?

Я могу понять, как это может быть полезно для макромаги, но почему это так?"особенность" в современном языке, таком как python?

Вы когда-нибудь использовали конкатенацию строковых литералов в производственном коде?

Ответы [ 10 ]

22 голосов
/ 24 марта 2010

Конечно, это простой способ заставить ваш код выглядеть хорошо:

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
17 голосов
/ 24 марта 2010

Это отличная функция, которая позволяет комбинировать строки препроцессора со строками.

// 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));
5 голосов
/ 24 марта 2010

Случаи, когда это может быть полезно:

  • Генерация строк, включающих компоненты, определенные препроцессором (это, пожалуй, самый большой вариант использования в 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 ".");
4 голосов
/ 07 февраля 2014

Я вижу несколько ответов C и C ++ , но ни один из них не отвечает на самом деле Почему или действительно, каково было обоснование этой функции? В C ++ эта функция взята из C99 , и мы можем найти обоснование для этой функции, перейдя к Обоснование международного стандарта - Языки программирования - C section 6.4.5 Строковые литералы , в которых написано ( выделено мое ):

Строка может быть продолжена на нескольких строках с помощью продолжения строки с обратным слешем и новой строкой, но для этого необходимо, чтобы продолжение строки начиналось с первой позиции следующей строки. Чтобы обеспечить более гибкую компоновку и решить некоторые проблемы предварительной обработки (см. §6.10.3), Комитет C89 ввел конкатенацию строковых литералов. Два строковых литерала в строке вставляются вместе без нулевого символа в середине, чтобы сделать один объединенный строковый литерал. Это дополнение к языку C позволяет программисту расширять строковый литерал за пределы конца физической строки, не используя механизм обратной косой черты - новой строки и тем самым разрушая схему отступов программы. Явный оператор конкатенации не был введен, потому что конкатенация - это лексическая конструкция , а не операция времени выполнения.

Python , что, по-видимому, имеет ту же причину, это уменьшает потребность в уродливом \ для продолжения длинных строковых литералов. Которая описана в разделе 2.4.2 Строковая литеральная конкатенация Справочник по языку Python .

3 голосов
/ 24 марта 2010

Из справочника лексического анализа python, раздел 2.4.2:

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

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

2 голосов
/ 24 марта 2010

Я не уверен насчет других языков программирования, но, например, C # не позволяет вам это делать (и я думаю, что это хорошо). Насколько я могу судить, большинство примеров, показывающих, почему это полезно в C ++, все равно будет работать, если вы сможете использовать какой-то специальный оператор для конкатенации строк:

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

Это может быть не так удобно, но, безусловно, безопаснее. В вашем мотивирующем примере код будет недействительным, если вы не добавите , для разделения элементов или + для объединения строк ...

1 голос
/ 10 июля 2014

Обоснование, расширение и упрощение ответа Шафика Ягмура: конкатенация строковых литералов возникла в C (следовательно, унаследована C ++), как и термин, по двум причинам (ссылки взяты из Обоснование для программирования ANSI C Язык ):

  • Для форматирования: разрешить длинным строковым литералам занимать несколько строк с правильным отступом - в отличие от продолжения строки, которое разрушает схему отступа ( 3.1.4 Строковые литералы ); и
  • Для магии макросов: разрешить построение строковых литералов с помощью макросов (через строковое форматирование) ( 3.8.3.2 Оператор # ).

Он включен в современные языки Python и D, потому что они скопировали его из C, хотя в обоих из них он был предложен как устаревший, так как он подвержен ошибкам (как вы заметили) и не нужен (поскольку можно просто иметь оператор конкатенации и постоянное свертывание для оценки времени компиляции; вы не можете сделать это в C, потому что строки являются указателями, и поэтому вы не можете их добавить).

Это не просто удалить, потому что это нарушает совместимость, и вы должны быть осторожны с приоритетом (неявная конкатенация происходит во время lexing, перед операторами, но замена этого на оператор означает, что вам нужно быть осторожным с приоритетом), поэтому, почему это все еще присутствует.

Да, в используемом производственном коде. Руководство по стилю Google Python : Длина строки указывает:

Когда буквенная строка не помещается на одной строке, используйте скобки для неявного объединения строк.

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

См. " Строковая конкатенация букв * " в Википедии для получения более подробной информации и ссылок.

1 голос
/ 24 марта 2010

Так что вы можете разделить длинные строковые литералы по строкам.

И да, я видел это в рабочем коде.

0 голосов
/ 20 марта 2011

Несмотря на то, что люди изъяли из моих слов слова о практическом использовании этой функции, до сих пор никто не пытался защитить выбор синтаксиса.

Насколько я знаю, опечатка, которая может просочиться в результате, вероятно, была просто пропущена. В конце концов, кажется, что устойчивость к опечаткам была не на виду у Денниса, как показано далее:

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

Кроме того, существует вероятность, что не стоит использовать дополнительный символ для объединения строковых литералов - в конце концов, с двумя из них ничего не поделаешь, и наличие символа может создайте соблазн, чтобы попытаться использовать его для конкатенации строк во время выполнения, что выше уровня встроенных функций языка C.

Некоторые современные языки более высокого уровня, основанные на синтаксисе Си, отбросили эту запись, предположительно, потому что она подвержена опечаткам. Но в этих языках есть оператор для конкатенации строк, такой как + (JS, C #), . (Perl, PHP), ~ (D, хотя это также сохранило синтаксис сопоставления C), и константа свертывания ( в скомпилированных языках, во всяком случае) означает, что производительность во время выполнения не снижается.

0 голосов
/ 24 марта 2010

У меня, конечно, есть и C, и C ++. Я не вижу особой связи между его полезностью и тем, насколько «современен» язык.

...