基本上,我想这样做:
#include "foo.h"
#include "bar.h"
static const unsigned line_after_includes = __LINE__;
int main()
{
foo(line_after_includes);
bar(line_after_includes);
return 0;
}
除此之外:
#include "foo.h"
#include "bar.h"
#define LINE_AFTER_INCLUDES __LINE__
int main()
{
FOO(LINE_AFTER_INCLUDES);
BAR(LINE_AFTER_INCLUDES);
return 0;
}
是否可以在LINE_AFTER_INCLUDES
定义的行上将__LINE__
扩展为LINE_AFTER_INCLUDES
的值,以便稍后可以将其与其他宏一起使用?我只是使用第一个代码片段中的变量,但我需要将值作为整数文字,因为我将在switch语句中使用它。另一种方法是
#define LINE_AFTER_INCLUDES 3 // MAKE SURE THIS IS ON LINE IT'S DEFINED AS!!!
这是丑陋的,难以维护。我会满足于此,但我会做一些比这个例子更复杂的事情......
答案 0 :(得分:3)
在@ Bathsheba的回答中给出了最好的方法:https://stackoverflow.com/a/24551912/1366431
typedef char LINE_AFTER_INCLUDES[__LINE__];
然后,您可以通过调用__LINE__
来访问该声明中sizeof(LINE_AFTER_INCLUDES)
的值,因为它的值已被固定为新声明的数组类型的一部分。 sizeof
是一个C级编译时常量,适用于switch
及相关事物(不需要除法:char
的大小保证为1,因为它是单位测量)。唯一的缺点是它是C级而不是预处理器级,因此它不能与#if
一起使用或用于标记粘贴。
(原创,我花了很多年的时间打字:)
所以这里的问题是宏定义是懒惰的;即,在实际需要将宏调用插入某种输出之前,不会扩展宏调用。因此,__LINE__
的扩张被推迟到为时已晚。
幸运的是,有一种方法可以在预处理器中强制进行评估 - 宏只需要输出某种的输出 - 不一定是程序正文。请记住,宏也可以扩展为形成预处理程序指令的参数 - 然后预处理程序指令 - 由强制扩展控制 - 能够创建进一步的定义。这个方便的观察是Boost的"evaluated slots" functionality的基础,它使用它来提供诸如急切评估和可变预处理器变量槽之类的东西。
不幸的是你不能使用__LINE__
的Boost插槽,因为它遇到了同样的问题 - 但我们可以窃取这个想法来产生两个相当不优雅的解决方案。他们每个人都以自己特殊的方式丑陋。
使用shell脚本生成大量(几百?)个include
个能够使用以下命名方案和内容的文件:
// linedefs/_42_.h
#define LINE_AFTER_INCLUDES 42
...然后使用如下:
#define GEN_LINE_INC(L) _GEN_LINE_S(_GEN_LINE_(L))
#define _GEN_LINE_(L) linedefs/_##L##_.h
#define _GEN_LINE_S(S) _GEN_LINE_S2(S)
#define _GEN_LINE_S2(S) #S
#include "foo.h"
#include "bar.h"
#include GEN_LINE_INC(__LINE__)
int main()
{
FOO(LINE_AFTER_INCLUDES);
BAR(LINE_AFTER_INCLUDES);
return 0;
}
换句话说,使用#include
指令强制扩展将__LINE__
转换为文件名的宏;包括该文件名为常量生成正确的值。这是不优雅的,因为它需要大量额外的文件和外部工具来生成它们,但它非常简单。
在#include
部分下方的主文件中插入一个又大又丑的块:
#include "foo.h"
#include "bar.h"
// <- This line is the one we generate the number for
#define LINE_BIT_0 0
#define LINE_BIT_1 0
#define LINE_BIT_2 0
#define LINE_BIT_3 0
#define LINE_BIT_4 0
#define LINE_BIT_5 0
#if (__LINE__ - 7) & 1
# undef LINE_BIT_0
# define LINE_BIT_0 1
#endif
#if (__LINE__ - 11) >> 1 & 1
# undef LINE_BIT_1
# define LINE_BIT_1 (1 << 1)
#endif
#if (__LINE__ - 15) >> 2 & 1
# undef LINE_BIT_2
# define LINE_BIT_2 (1 << 2)
#endif
#if (__LINE__ - 19) >> 3 & 1
# undef LINE_BIT_3
# define LINE_BIT_3 (1 << 3)
#endif
#if (__LINE__ - 23) >> 4 & 1
# undef LINE_BIT_4
# define LINE_BIT_4 (1 << 4)
#endif
#if (__LINE__ - 27) >> 5 & 1
# undef LINE_BIT_5
# define LINE_BIT_5 (1 << 5)
#endif
#define LINE_AFTER_INCLUDES (LINE_BIT_0 | LINE_BIT_1 | LINE_BIT_2 | LINE_BIT_3 | LINE_BIT_4 | LINE_BIT_5)
int main() ...
此版本使用#if
指令强制扩展__LINE__
宏并将其转换为位标志,然后在最后重新组合。这是高度不优雅,因为它依赖于预先计算每个#if
和块顶部之间的距离,因为__LINE__
在块的过程中评估为不同的值;并且它不能被分解并隐藏在单独的文件中,否则__LINE__
将无效。但它仍然有效,并且不需要外部工具。
(如果您有大量#include
行,将其扩展到6位以上应该很简单。)
另一方面,这对我来说听起来像是X / Y问题。必须有__LINE__
的替代方案才能更好地发挥作用。如果你计算#include
d个文件的数量,也许你可以使用类似于每行末尾增加Boost.Counter的行?这样,您也不会受到格式化更改的影响(例如#include
部分中的空白行)。