#include <stdio.h> #define LINE_FILE ("Line %d of file %s", __LINE__, __FILE__) int main(void) { const char* str = LINE_FILE; printf("%s\n", str); printf("Line %d of file %s\n", __LINE__, __FILE__); }
第一个print语句只打印文件名而不是整行。
5anewei61#
如果你想要一个像这样的字符串预格式化,这里是你如何做到这一点:
#include <stdio.h> #define STR_IMPL(x) #x #define STR(x) STR_IMPL(x) #define LINE_FILE ("Line " STR(__LINE__) " of file " __FILE__) int main() { printf("%s\n", LINE_FILE); }
voj3qocg2#
实际上 * 解释 * 为什么代码不工作以及如何使其工作:
const char* str = ("Line %d of file %s", __LINE__, __FILE__);结果是乱码。
const char* str = ("Line %d of file %s", __LINE__, __FILE__);
"these things"
%d
%s
printf
sprintf
char str[] = {'A','B','C','\0'};
,
TL;DR对逗号运算符的简化是,它丢弃了左边的所有操作数,只使用最右边的操作数作为结果。因此,您的表达式最终100%等效于const char* str = __FILE__;,因此,当您尝试打印str时,只有文件名的结果令人惊讶。
const char* str = __FILE__;
str
strcpy
strcat
C * 预处理器 * 有一些锦囊妙计。预处理器是指执行的第一个编译器阶段,当编译器通过你的代码,以确保一切似乎是有效的C“一眼”。预处理器将LINE_FILE替换为宏体,然后依次将__LINE__和__FILE__替换为实际数据。但它也能够连接字符串文字。在C语言中,这是通过写两个字符串字面量,中间有一个或多个空格来完成的,例如"hello" "world",然后将其连接为"helloworld"。
LINE_FILE
__LINE__
__FILE__
"hello" "world"
"helloworld"
"file " __FILE__
"file test.c"
关于字符串化宏的TL;DR是“字符串化运算符”#总是首先应用于它所在的宏中,然后才扩展该宏中的所有其他标记。因此,如果我们编写一个宏#define STR(s) #s并传递STR(__LINE__),我们 * 将 * 得到一个字符串字面量,但它将变成"__LINE__",这不是我们想要的。为了解决这个问题,我们需要创建一个帮助宏,在调用包含#的宏之前,它首先扩展所有预处理器标记。就像这样:
#
#define STR(s) #s
STR(__LINE__)
"__LINE__"
#define STR_(s) #s #define STR(s) STR_(s)
const char* str = LINE_FILE;
完整示例:
#include <stdio.h> #define STR_(s) #s #define STR(s) STR_(s) #define LINE_FILE "Line " STR(__LINE__) " of file " __FILE__ int main(void) { puts(LINE_FILE); }
输出量:
Line 9 of file example.c
1cosmwyk3#
请记住,宏是一个简单的替换,因此str实际上是
该表达式由三个子表达式组成,使用,运算符连接,该运算符计算并忽略其第一个参数,然后计算并产生其第二个参数。所以它相当于
"Line %d of file %s"; __LINE__; const char* str = __FILE__;
希望这能帮助你明白为什么你会得到这样的结果。
yptwkmov4#
很难说你到底想要什么。请记住,宏本质上只是一个美化的复制和粘贴,所以这个宏不是很有用:
#define LINE_FILE ("Line %d of file %s", __LINE__, __FILE__)
我想你要找的是一个宏,它用__LINE__和__FILE__调用printf。像这样的东西应该可以做到:
#define LINE_FILE printf("Line %d of file %s", __LINE__, __FILE__)
或者你想把它存储在一个缓冲区中,用于其他具有“类似函数的宏”的东西:
#define LINE_FILE(buf_, n_) \ snprintf(buf_, n_, "Line %d of file %s", __LINE__, __FILE__) int main() { char buf[50]; LINE_FILE(buf, sizeof(buf)); }
9udxz4iz5#
("Line %d of file %s", __LINE__, __FILE__)使用printf创建字符串。您需要:
("Line %d of file %s", __LINE__, __FILE__)
printf LINE_FILE;
或
#define LL "Line %d of file %s\n", __LINE__, __FILE__ #define LINE_FILE (LL) #define LINE_FILE1(name) char *name; { size_t len; name = malloc(len = (snprintf(NULL, 0, LL) + 1)); \ if(name) snprintf(name, len, LL);} int main(void) { printf LINE_FILE; printf("Line %d of file %s\n", __LINE__, __FILE__); LINE_FILE1(str); printf("%s", str); free(str); }
5条答案
按热度按时间5anewei61#
如果你想要一个像这样的字符串预格式化,这里是你如何做到这一点:
voj3qocg2#
实际上 * 解释 * 为什么代码不工作以及如何使其工作:
const char* str = ("Line %d of file %s", __LINE__, __FILE__);
结果是乱码。"these things"
)中的%d
和%s
等格式说明符实际上在C中没有任何特殊意义。碰巧的是,printf
系列函数为这些函数定义了特定的含义,因为printf
系列函数在内部使用输入的运行时字符串解析。而且我们希望这也能在编译时完成,所以sprintf
等是不好的。char str[] = {'A','B','C','\0'};
那样的初始化列表,也不是函数调用。因为你把表达式放在括号里,所以它最终会成为一个子表达式,编译器会理解这一点,就好像你想使用特殊的逗号运算符,
一样。What does the comma operator , do?。TL;DR对逗号运算符的简化是,它丢弃了左边的所有操作数,只使用最右边的操作数作为结果。因此,您的表达式最终100%等效于
const char* str = __FILE__;
,因此,当您尝试打印str
时,只有文件名的结果令人惊讶。strcpy
和strcat
等函数完成,但也可以在编译时连接字符串。C * 预处理器 * 有一些锦囊妙计。预处理器是指执行的第一个编译器阶段,当编译器通过你的代码,以确保一切似乎是有效的C“一眼”。预处理器将
LINE_FILE
替换为宏体,然后依次将__LINE__
和__FILE__
替换为实际数据。但它也能够连接字符串文字。在C语言中,这是通过写两个字符串字面量,中间有一个或多个空格来完成的,例如"hello" "world"
,然后将其连接为"helloworld"
。__FILE__
是一个字符串,我们可以写"file " __FILE__
,然后预处理器将其转换为"file test.c"
等。然而,对于整数__LINE__
,情况并非如此。__LINE__
转换为字符串字面量。只要__LINE__
是编译时常量,预处理器也可以这样做。我们将使用“字符串化宏”Stringification - how does it work?。关于字符串化宏的TL;DR是“字符串化运算符”
#
总是首先应用于它所在的宏中,然后才扩展该宏中的所有其他标记。因此,如果我们编写一个宏#define STR(s) #s
并传递STR(__LINE__)
,我们 * 将 * 得到一个字符串字面量,但它将变成"__LINE__"
,这不是我们想要的。为了解决这个问题,我们需要创建一个帮助宏,在调用包含#
的宏之前,它首先扩展所有预处理器标记。就像这样:const char* str = LINE_FILE;
,否则它将被分配到声明str
的行和文件中,而不是我们选择打印它的行。完整示例:
输出量:
1cosmwyk3#
请记住,宏是一个简单的替换,因此
str
实际上是该表达式由三个子表达式组成,使用
,
运算符连接,该运算符计算并忽略其第一个参数,然后计算并产生其第二个参数。所以它相当于希望这能帮助你明白为什么你会得到这样的结果。
yptwkmov4#
很难说你到底想要什么。请记住,宏本质上只是一个美化的复制和粘贴,所以这个宏不是很有用:
我想你要找的是一个宏,它用
__LINE__
和__FILE__
调用printf
。像这样的东西应该可以做到:或者你想把它存储在一个缓冲区中,用于其他具有“类似函数的宏”的东西:
9udxz4iz5#
("Line %d of file %s", __LINE__, __FILE__)
使用printf
创建字符串。您需要:
或