14

我最近被一个微妙的虫子咬了。

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

如果你有神一样的代码审查能力,你会注意到我忘记了,after "two"

经过相当大的努力找到该错误后,我不得不问为什么有人会想要这种行为?

我可以看到这可能对宏魔术有用,但是为什么这是现代语言(如 python)中的“功能”?

您曾经在生产代码中使用过字符串文字连接吗?

4

11 回答 11

22

当然,这是让您的代码看起来不错的简单方法:

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
于 2010-03-24T00:12:54.563 回答
17

这是一个很棒的功能,它允许您将预处理器字符串与您的字符串结合起来。

// 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));
于 2010-03-24T00:12:02.413 回答
5

这可能有用的情况:

  • 生成包含由预处理器定义的组件的字符串(这可能是 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 ".");
于 2010-03-24T00:11:33.183 回答
4

我看到了几个CC++的答案,但没有一个真正的答案为什么或这个功能的基本原理是什么?在C++中,这是来自C99的特性,我们可以通过转到国际标准的基本原理—编程语言—C部分6.4.5 字符串文字来找到该特性的基本原理,其中说(强调我的):

使用反斜杠-换行符续行可以跨多行继续字符串,但这要求字符串的续行从下一行的第一个位置开始。为了允许更灵活的布局,并解决一些预处理问题(参见 §6.10.3),C89 委员会引入了字符串文字连接。将连续的两个字符串文字粘贴在一起,中间没有空字符,以组成一个组合字符串文字。对 C 语言的这种添加允许程序员将字符串文字扩展到物理行的末尾之外,而不必使用反斜杠换行机制,从而破坏程序的缩进方案。没有引入显式连接运算符,因为连接是词法构造而不是运行时操作。

Python似乎有同样的原因,这减少了丑陋\的继续长字符串文字的需要。这在The Python Language Reference的第2.4.2 节 String literal concatenation中有所 介绍。

于 2014-02-07T14:12:13.867 回答
3

我不确定其他编程语言,但例如 C# 不允许你这样做(我认为这是一件好事)。据我所知,如果您可以使用一些特殊的运算符进行字符串连接,那么大多数说明为什么这在 C++ 中有用的示例仍然有效:

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

这可能不太舒服,但肯定更安全。,在您的激励示例中,除非您添加到单独的元素或+连接字符串,否则代码将无效......

于 2010-03-24T00:30:23.177 回答
3

来自 python 词法分析参考,第 2.4.2 节:

此功能可用于减少所需的反斜杠数量,方便地将长字符串拆分为长行,甚至可以为部分字符串添加注释

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

于 2010-03-24T00:34:03.943 回答
2

这样您就可以跨行拆分长字符串文字。

是的,我已经在生产代码中看到了它。

于 2010-03-24T00:11:27.660 回答
1

出于基本原理,扩展和简化 Shafik Yaghmour 的答案:字符串文字连接起源于 C(因此由 C++ 继承),正如该术语一样,有两个原因(参考来自ANSI C Programming Language 的基本原理):

  • 对于格式化:允许长字符串文字以适当的缩进跨越多行 - 与行继续相反,它破坏了缩进方案(3.1.4 字符串文字);和
  • 对于宏魔术:允许通过宏(通过字符串化)(3.8.3.2 # 运算符)构造字符串文字。

它包含在现代语言 Python 和 D 中,因为它们是从 C 中复制而来的,尽管在这两种语言中都建议弃用它,因为它容易出错(正如您所注意到的)并且不必要(因为一个只能有一个连接用于编译时评估的运算符和常量折叠;你不能在 C 中这样做,因为字符串是指针,所以你不能添加它们)。

删除它并不简单,因为这会破坏兼容性,并且您必须注意优先级(隐式连接发生在词法分析期间,在运算符之前,但是用运算符替换它意味着您需要注意优先级),因此它为什么仍然存在.

是的,它在使用的生产代码中。Google Python 样式指南行长指定:

当文字字符串不适合单行时,请使用括号进行隐式行连接。

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

有关更多详细信息和参考,请参阅 Wikipedia 上的“<a href="https://en.wikipedia.org/wiki/String_literal_concatenation" rel="nofollow">字符串文字连接”。

于 2014-07-10T04:00:17.527 回答
0

我当然有 C 和 C++。顺便说一句,我看不出它的实用性与语言的“现代”程度之间有多大关系。

于 2010-03-24T00:10:59.467 回答
0

尽管人们已经从我口中说出了有关该功能的实际用途的话,但到目前为止还没有人试图为语法选择辩护。

据我所知,结果可能漏掉的错字可能只是被忽略了。毕竟,对错别字的鲁棒性似乎并不在 Dennis 的考虑范围之内,如下所示:

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

此外,有一种可能的观点是,使用额外的符号来连接字符串文字是不值得的——毕竟,用它们中的两个可以做的事情不多,并且在那里有一个符号可能会产生诱惑尝试将其用于运行时字符串连接,这在 C 的内置功能级别之上。

一些基于 C 语法的现代高级语言已经放弃了这种表示法,大概是因为它容易出现拼写错误。但是这些语言有一个用于字符串连接的运算符,例如+(JS,C#),.(Perl,PHP),~(D,尽管这也保留了 C 的并列语法),并且常量折叠(无论如何在编译语言中)意味着存在没有运行时性能开销。

于 2011-03-20T14:52:42.730 回答
0

我在野外看到的另一个鬼鬼祟祟的错误是人们认为两个单引号是一种转义引号的方法(例如,它通常用于CSV 文件中的双引号),所以他们会写如下内容在python

print('Beggars can''t be choosers')

它输出Beggars cant be choosers而不是Beggars can't be choosers所需的编码器。

至于最初的“为什么”问题:为什么这是像 python 这样的现代语言的“功能”?- 在我看来,我同意 OP,不应该这样。

于 2021-06-08T17:41:40.170 回答