为什么允许串联字符串文字?

时间:2010-03-24 00:08:05

标签: python c++ c d string-literals

我最近被一个微妙的错误所困扰。

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"

经过相当大的努力才能找到这个bug,我必须问为什么有人会想要这种行为?

我可以看到这对宏魔术有什么用处,但是为什么这是像python这样的现代语言中的“特征”?

您是否曾在生产代码中使用字符串文字串联?

11 个答案:

答案 0 :(得分: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);

有很多定义的,如果您有类型大小要求,它们可以派上用场。全部检查at this link。几个例子:

PRIo8 PRIoLEAST16 PRIoFAST32 PRIoMAX PRIoPTR

答案 1 :(得分: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));

答案 2 :(得分: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 ".");

答案 3 :(得分:4)

我看到了几个 C C ++ 的答案,但没有真正回答为什么或者这个功能的理由是什么?在 C ++ 中,此功能来自 C99 ,我们可以通过转到Rationale for International Standard—Programming Languages—C部分6.4.5 字符串文字找到此功能的基本原理表示(强调我的):

  

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

Python 似乎有相同的原因,这减少了丑陋的\继续长字符串文字的需要。这部分将在2.4.2 String literal concatenation部分中介绍 Python语言参考

答案 4 :(得分:3)

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

  

此功能可用于减少   要分割的反斜杠数量   长串方便   行,甚至添加评论   字符串的一部分

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

答案 5 :(得分:2)

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

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

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

答案 6 :(得分:1)

这样你就可以跨行分割长字符串文字。

是的,我在生产代码中看过它。

答案 7 :(得分:1)

对于理由,扩展和简化Shafik Yaghmour的答案:字符串文字连接起源于C(因此由C ++继承),该术语也是如此,原因有两个(引用来自 Rationale for the ANSI C Programming Language ):

  • 用于格式化:允许长字符串文字跨越多行并使用适当的缩进 - 与行继续相反,后者会破坏缩进方案(3.1.4 String literals);和
  • 对于宏魔法:允许通过宏构建字符串文字(通过字符串化)(3.8.3.2 The # operator)。

它包含在现代语言Python和D中,因为它们是从C复制的,尽管在这两种情况下它都被提议用于弃用,因为它容易出错(如你所注意到的)并且是不必要的(因为它可以只是有一个连接运算符和constant folding用于编译时评估;你不能在C中执行此操作,因为字符串是指针,所以你不能添加它们。)

删除并不简单,因为这会破坏兼容性,你必须小心优先级(在lexing期间,在运算符之前发生隐式连接,但用运算符替换它意味着你需要注意优先级),这就是为什么它仍然存在。

是的,它在使用过的生产代码中。 Google Python Style GuideLine length指定:

  

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

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

有关详细信息和参考资料,请参阅维基百科上的“String literal concatenation”。

答案 8 :(得分:0)

我当然有C和C ++。另一方面,我认为它的效用与语言的“现代”程度之间并没有多大关系。

答案 9 :(得分:0)

虽然人们已经对这个功能的实际用法不以为然,但到目前为止还没有人试图捍卫语法的选择。

据我所知,结果可能会漏掉的拼写错误可能只是被忽略了。毕竟,似乎对于错别字的强大不在丹尼斯的脑海中,如下所示:

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

此外,可能的观点是,不值得使用额外的符号来连接字符串文字 - 毕竟,其中两个没有其他可以做的事情,并且在那里有一个符号可能创建诱惑试图将它用于运行时字符串连接,这超出了C内置功能的级别。

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

答案 10 :(得分:0)

我在野外看到的另一个偷偷摸摸的错误是人们认为两个单引号是一种转义引号的方法(因为它常用 for double quotes in CSV files, for example),因此他们会在python

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

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

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