使用多个带引号的字符串初始化C字符串

时间:2009-12-01 01:22:37

标签: c string

我认为可以使用一个且只引用一个字符串来初始化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 个答案:

答案 0 :(得分:12)

compiler会自动连接相邻的字符串。

这对于提高可读性非常有用,如您的示例或某些预处理器函数:

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

LOG("HeyHey");

非常人为的例子,但是明白了这一点。

答案 1 :(得分:2)

因为编译器认为相邻的引用字符串是同一字符串的一部分。 C语法特别允许这样做。

答案 2 :(得分:2)

不要与字符串数组混淆:

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

您发布的是一个字符串。

答案 3 :(得分:2)

您的初始值设定项只包含一个字符串文字。看起来像多个“”封闭的字符串文字实际上会在翻译的第6个阶段(在预处理之后)合并为单个字符串文字。

答案 4 :(得分:2)

相邻的字符串文字是连接的,这有两种方法:组合字符串和可视化多行字符串文字,如上所述。比较一下代码的外观:

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__也是deprecated,但其余的都很方便,这是一个体面的“真实”例如,恕我直言。)

该代码中提到的其他问题需要注意:

  • 单个#是预处理器stringize运算符(##是另一个特殊的预处理器运算符,用于标记粘贴)
  • 没有第二个stringize宏,您将获得"filename.c:__LINE__"
  • 使用do-while不会破坏if-else,并且要求将宏用作语句而不是表达式
    • 防止用作表达式并不总是有用,但它是你想要的类似断言的宏

打破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();
  }
}