带有预定义宏的字符串连接的Printf在C中具有格式说明符

时间:2016-06-30 12:22:46

标签: c macros

我在Windows和MSVC中编程。我知道有两种方法可以编写DEBUG_PRINT语句:

printf(__FUNCTION__": Error code: %x\n", ErrorCode); 
printf("%s: Error code: %x\n", __FUNCTION__, ErrorCode);

将预定义的宏连接到这样的字符串是否可以?我不知道预定义的宏如__FUNCTION____LINE__是否是合法的字符串文字。直观地说,在C中处理这样的字符串似乎是一种危险的方式。

这两者有什么区别?由于我使用/ FAcs编译器选项将代码片段输出到程序集,我真的看不出太大差异。

4 个答案:

答案 0 :(得分:2)

首先,__FUNCTION__不在C标准中,你应该使用__func__代替(除了微软决定在他们的C编译器中跳过对它的支持)。

第二个__FUNCTION__ / __func__"宏"实际上并不是一个宏(或者至少不是正常的 - 微软的编译器似乎行为不同),它的行为更像是局部变量,因此它不是字符串连接的候选者。您应该使用字符串格式(因为这将确保您的代码变得更加可移植)。

__LINE__宏(是一个宏),但它不能直接与字符串连接一起使用,因为它不会扩展为字符串 - 它会扩展为一个数字(由方式在其他情况下可能有用)。但是,您可以使用预处理器对其进行字符串化(XSTR宏将首先扩展它的参数然后对结果进行字符串化,而STR在对字符串进行字符串化之前不会展开它的参数):

#define STR(x) # x
#define XSTR(x) STR(x)

printf("I'm on line #" XSTR(__LINE__));

__FILE__宏(也是一个宏)确实扩展为一个字符串文字,它可以直接与字符串连接一起使用。

您没有看到任何差异的原因是编译器知道printf做了什么,并且可以将其用于优化。它会发现它不需要依赖printf代码来在运行时扩展%s,因为它可以在编译时完成它。

答案 1 :(得分:1)

前者将__FUNCTION__中的函数名与编译时的格式字符串连接起来。第二个将在运行时将其格式化为输出。

这假设它是一个预定义的宏(它不是标准的)。 MSVC将__FUNCTION__作为正确的字符串文字,而GCC则没有。

GCC支持

__LINE__,并扩展为十进制整数,即不是字符串。

出于性能原因,我建议在可能的情况下始终使用第一种方式,即当两个字符串是编译时常量时。像往常一样,要付出代价:字符串池会更大,因为每次使用宏都会创建一个唯一的格式字符串。对于桌面级系统,这可能是微不足道的。

答案 2 :(得分:0)

不同之处在于,在第一种情况下,字符串文字在编译器转换阶段与格式字符串连接,而在第二种情况下,它在运行时被读入。所以第一种方法要快得多。

如果您知道宏是预定义的字符串文字,我就不会发现代码有任何问题。

话虽如此,我不知道__FUNCTION__是什么。有一个标准的C宏__func__,但它不是一个字符串文字,应该被视为一个const char数组。

__LINE__是一个标准的C宏,它将源文件行作为整数。

答案 3 :(得分:0)

感谢您的回答。看起来第一种方式是一个合法的文字字符串连接,它只是在构建时,它更快,只是占用空间。

我想我会坚持第一种方式。再次感谢。