是否有广泛可用的宽字符变体 `__FILE__`?

18

在C++程序中,通常可以使用__LINE____FILE__,包括GCC等许多工具链。

在GCC下,__LINE__的计算结果为类型为int的表达式;
__FILE__的计算结果为char const[N],其中N是适当的值。

  • 是否有任何主要的工具链提供与类型wchar const[N]相等的__FILE__等效项?
  • 如果有,它是什么?

参见:https://dev59.com/kG855IYBdhLWcg3wSSKl?rq=1 - Lightness Races in Orbit
我不知道有任何本地支持此功能的程序。任何支持此功能的链条都是特定于该链条的,因为标准只要求“字符字符串文字”定义(§16.8)。我认为我们大多数人已经找到了解决方法,并且使用了其他字符串文字宏扩展,程度不同 =P - WhozCraig
5个回答

40
您可以制作自己的 WFILE:
#define WIDE2(x) L##x
#define WIDE1(x) WIDE2(x)
#define WFILE WIDE1(__FILE__)

测试了包含非ASCII字符和文件名为马克.cpp的情况:

#include <stdio.h>
#include <io.h>
#include <fcntl.h>

#define WIDE2(x) L##x
#define WIDE1(x) WIDE2(x)
#define WFILE WIDE1(__FILE__)

int main() {
    _setmode(_fileno(stdout), _O_U16TEXT); // required for Unicode output to console
    wprintf(L"%s\n", WFILE);
}

演示(从cmd.exe运行并安装了中文语言支持):

C:\>cl /W4 /nologo 马克.cpp
马克.cpp

C:\>马克.exe
马克.cpp

2
@zar 试一下,你就会知道为什么了。 - Mark Tolonen
5
“WFILE” 不需要任何参数。你可以使用 “WIDE1(FILE)” 来替代,这将有效。仅使用 “WIDE2(FILE)” 将会生成 “L__FILE__”,这是错误的。至少需要双层扩展 “__FILE__” 宏,第三层是为了只需键入“WFILE”。请注意,翻译时不得添加解释或其他内容。 - Mark Tolonen
好知道,谢谢。因为当涉及到工作时,即使 _T(__FILE__) 对我也起作用,但我被告知这不是正确的解决方案。 - zar
虽然这提供了一个文件的当前路径,但如果当前文件具有非ASCII字符(在MSVC 2019中测试),它将无法工作。 - ScaledLizard
@ScaledLizard请查看更新。你必须定义“它无法工作”的具体情况。 - Mark Tolonen
显示剩余4条评论

1
在Visual Studio中,只需使用_T()将其括起来,例如:
TRACE( _T("function = %s"), _T(__FUNCTION__);

不好意思,看一下Doug五年前的回答以及评论历史记录。这是错误的。 - Lightness Races in Orbit

1

使用:

WIDE(MEXPAND(__FILE__))

并且

WIDE(STRINGIFY(__LINE__))

或者将__LINE__替换为需要字符串化的任何内容,并将__FILE__替换为您想要扩展的任何宏字符串字面量。

使用以下定义:

#define STRINGIFY2(m) #m
#define MEXPAND(m) m
#define STRINGIFY(m) STRINGIFY2(m)
#define WIDE(m) L ## m

使用示例:

#define AssertBreakMethod DebugBreak

#define AssertBreakForce(expr) \
  do \
  { \
    if (!(expr)) \
    { \
      OutputDebugStringW(WIDE(MEXPAND(__FILE__)) \
          WIDE("(") WIDE(STRINGIFY(__LINE__)) \
          WIDE("): Assertion failed: ") \
          WIDE(#expr) WIDE("\n")); \
      AssertBreakMethod(); \
    } \
  } \
  while (0)

请注意,OutputDebugString 的整个参数在编译时静态组装成一个单独的字符串文字。
宏字符串化的技巧是通过另一个宏传递它。当 __FILE__ 传递给 MEXPAND 时,它会在那个时候展开。MEXPAND 返回其参数,现在是一个字符串。然后可以在那里放置前导 L 使其变宽。
STRINGIFY 做同样的技巧,它将其参数传递到 STRINGIFY2 中,该参数将被扩展为行号(此时看起来像整数),然后 STRINGIFY2 在其前面放置 # 符号,将整数字符串化。

2
请参考其他答案。在应用##运算符之前,宏扩展将被抑制,所以_T(__FILE__)会生成L__FILE__。此外,不要定义保留名称,即使是为了模拟另一个平台。特别是对于只有两个字符的情况——_T很可能在其他编译器中代表其他含义。最好使用#define WIDEN _T来定义一个非保留名称,以便跨平台使用。 - Potatoswatter
@Potatoswatter 很好的发现。我最近修改了这段代码,糟糕。 - doug65536
是的,我考虑过使用新名称,但为什么要让问题变得更加混乱呢?人们通常知道 _T 代表什么,如果你有一个宏来表示它,就用它吧,否则就使用 L。 - doug65536
前面的例子也需要修正答案。由于我没有Windows,所以不确定该怎么做。嗯,如果_T是这样定义的,我不确定为什么它会被认为是一种供大众使用的实用工具。 - Potatoswatter
因为 _T(__FILE__) 会扩展为 L__FILE__ - Potatoswatter
显示剩余3条评论

0

我本来想把这个答案作为早期回复的评论,但由于没有最低50个声望来评论,所以不允许...

在Visual Studio中,_T(__FILE__)不会扩展到L__FILE__,除非您修改了tchar.h头文件中_T的标准定义。如果您正在寻找当前文件和函数的宽版本,则5年前_T(__FILE__)和_T(__FUNCTION__)有效,今天仍然有效。

_T(x)被定义为__T(x),当定义了_UNICODE时,它被定义为L##x,否则为x。因此,_T(__FILE__)扩展为类似__T("my_file.c")的内容,然后根据_UNICODE扩展为L"my_file.c"或"my_file.c"。在声称它们无法工作之前测试它们是有用的。


不知道你在这里跟谁说话。 - Lightness Races in Orbit
你到底不明白什么? - Jim Monte
最初的问题是,是否有任何主要的工具链提供了 wchar const[N] 类型的 _FILE_ 等效项?在 Visual Studio 中,T(_FILE) 将生成 __FILE__ 的宽版本。 - Jim Monte
那么就这么说吧。根据你自己的承认,这个“答案”似乎是试图回应某人关于别处的某事的一种尝试。 - Lightness Races in Orbit
实际上,我本来想把我的答案分成两个评论,因为这样可以向@zar解释在Visual Studio中为什么_T(__FILE__)有效以及他的TRACE()宏是如何工作的。然而,我并没有承认我的答案不是一个完整的答案。事实上,这是目前为止唯一一个完整回答,给出了被要求的主要工具链及其等效的宽版本。MT和doug65536的答案中的信息是正确的,但并未回答问题,因为它们没有识别工具链中的现有功能。zar的答案没有提到__FILE__宏。 - Jim Monte
在MinGW中,使用tchar.h版本中定义的_T(x)定义,_T(__FILE__)是与此问题相关的答案。内部宏名称与Visual Studio中的名称不同,但效果相同。 - Jim Monte

-2
例如使用常量 auto name = L"" __FUNCTION__;

你可能是想用 wchar_t,但这样行不通,而且宏也错了。 - Lightness Races in Orbit
抱歉打错字了。在引号之间和__FUNCNAME__之间有一个空格。在Visual Studio(例如版本2017)中运行良好。#define __W_FUNCTION__ L"" __FUNCTION__<br/><br/>const wchar_t *msg = L"" __FUNCTION__ ": one message.";<br/>const wchar_t *msg2 = __W_FUNCTION__ ": one more message.";<br/>它利用编译器连接相邻字符串文字的事实。(<br/>是换行符,在我的计算机上不起作用)。 - Big Steak On The Grill
虽然你仍在谈论错误的宏(我并不是在问关于__FUNCNAME__,这个只在VS中有效),但是似乎可以工作这里是标准文档:似乎存在实现定义的结果是否模棱两可。这可能是一个好答案的基础。 - Lightness Races in Orbit
我使用了 __FUNCTION__。你的例子是 __FILE__。尽管如此,我的方法与其他预定义宏一起工作得很好,这些宏通常只提供为 const char[](例如使用建议的 define 语句)。我在 VS 中检查了你的代码片段,它在那里可以工作。如果您不介意,请更改给定解决方案的评级。 - Big Steak On The Grill
如果您更正了错误的宏,并给出一些合理的理由,说明为什么这是有效的、明确定义的和可移植的,那我会很高兴! - Lightness Races in Orbit
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接