我正在尝试按如下方式编译 WinApi 应用程序,但我没有得到输出 -
#include <windows.h>
#define UNICODE
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
wprintf(TEXT("%s"), TEXT("Hello")) ;
}
我还有 GCC 的输出 -
app.c: In function 'WinMain':
app.c:9:3: warning: implicit declaration of function 'wprintf'; did you mean 'wsprintf'? [-Wimplicit-function-declaration]
9 | wprintf(TEXT("%s"), TEXT("Hello")) ;
| ^~~~~~~
| wsprintf
但是,如果我按照以下方式重写函数,我会得到正确的输出,但编译器会出现相同的警告 -
#include <windows.h>
#define UNICODE
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
wprintf(L"%s", L"Hello") ;
}
我正在使用
GCC 13.2.0 from MSYS32
并编译此应用程序,没有任何标志,如下所示:gcc app.c -o app
wprintf(TEXT("%s"), TEXT("Hello")) ;
不会扩展为 wprintf(L"%s", L"Hello") ;
吗?我们先来说第二个问题:
这个编译器警告是什么意思?
警告指出您正在使用 C 编程语言的一项功能,该功能非常危险,以至于在 C99 中它被提升为错误:每当编译器看到带有它不知道的函数名称的函数调用表达式时,它都会继续执行并发明声明。以下示例可以编译,尽管它不应该编译。
不幸的是,链接器以某种方式发现了
wprintf()
符号并生成了一个它不应该有的二进制文件。更糟糕的是,GCC 默认不实现 C99,所以通过 -std=c99
也救不了你。
wprintf()
,您必须#include <wchar.h>
。这引入了 wprintf()
的声明,以便编译器可以生成正确的函数调用代码。
第一个问题需要更多文字来解释。主要收获是:
不要使用通用文本映射。
它们的引入是为了帮助开发人员从 Win9x 过渡到基于 WinNT 的系统,方法是提供一个粗略的转换层来解释不同的默认字符编码(Win9x 的 ANSI 代码页编码和 WinNT 的 UCS-2/UTF-16)。
为什么第一个变体没有输出,而第二个变体有输出?
它们并不等同。第一段代码构造了narrow字符串文字。使用
TEXT()
宏没有任何作用。具体问题在这里:
#include <windows.h>
#define UNICODE
这指示编译器处理来自
UNICODE
预处理器符号。这样做不会追溯改变 TEXT()
的含义:它仍然只是一个空操作。
这就引出了你没有问的第三个问题:
为什么这还能编译?
这是C编程语言的另一个特点:指针只是指针。事实上,您可以将类型与指针对象关联起来,这一事实会让编译器“不为所动”(模警告)。它要求一个指针,它得到一个指针,就是这样。 更改顺序将使两个程序相同。但这仍然是错误的,即使无关紧要。
再次强调,
,但如果您必须使用,至少不要弄错。默认情况下“犯错”,让我们快速了解一下规则:
通用文本映射通过预处理器符号UNICODE
_UNICODE
、MBCS
和 _MBCS
进行控制。始终在编译器命令行上传递它们,例如 -D _UNICODE
。预处理器符号控制两个独立的区域:Win32 API 表面 (UNICODE
MBCS
) 和 C 运行时 (_UNICODE
/_MBCS
)。 TEXT 与 _TEXT 与 _T,以及 UNICODE 与 _UNICODE更详细地解释了这一点。 字符串文字必须包含在
TEXT()
_TEXT()
/_T()
宏中。根据功能所属区域选择正确的宏,例如 CRT 为 _TEXT()
。始终调用函数的通用文本映射。 CRT 的(非标准)扩展带有 _t
_tprintf()
。对于 Win32 API,通用文本映射没有 A
或 W
后缀。
#include <windows.h>
#include <wchar.h>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
_tprintf(_TEXT("%s"), _TEXT("Hello")) ;
}
如果您不使用通用文本映射,您可能会忘记在这里阅读的所有内容。这样做你不会失去任何东西。