优秀的编程知识分享平台

网站首页 > 技术文章 正文

学习阅读C++编译器错误:函数声明中的荒谬错误

nanyue 2025-01-20 15:37:19 技术文章 4 ℃


在软件开发的过程中,我们经常会遇到各种编译器错误。这些错误有时让人摸不着头脑,但它们实际上是编译器试图告诉我们代码中存在的问题。今天,我们将通过一个具体的例子,探讨如何理解和解决C++编译器中出现的一些看似荒谬的错误。

问题背景

一位客户希望在其应用程序中添加XAML支持,因此他们包含了(除其他事项外)头文件winrt/Windows.UI.Xaml.h。但是,仅仅包含这个头文件就产生了一连串可怕的错误,这些错误始于:

winrt\impl\Windows.UI.Xaml.0.h(4323,28): warning C4003: not enough arguments for function-like macro invocation 'ErrorMessage'
winrt\impl\Windows.UI.Xaml.0.h(4323,28): error C2146: syntax error: missing ')' before identifier 'ErrorMessageString'
winrt\impl\Windows.UI.Xaml.0.h(4323,28): error C3646: 'ErrorMessageString': unknown override specifier
winrt\impl\Windows.UI.Xaml.0.h(4323,28): error C2059: syntax error: ')'
winrt\impl\Windows.UI.Xaml.0.h(4323,48): error C2238: unexpected token(s) preceding ';'

这些错误看起来非常严重,但它们究竟是怎么回事?

错误分析

错误来自于以下代码行:

template <typename D>
struct consume_Windows_UI_Xaml_IExceptionRoutedEventArgs
{
    [[nodiscard]] auto ErrorMessage() const;
};

这行代码看起来是一个完全正常的函数声明。那么,为什么编译器会不高兴呢?

仔细观察第一个错误消息:

not enough arguments for function-like macro invocation 'ErrorMessage'

等等,“函数式宏调用”?这意味着编译器认为你正在尝试使用一个名为ErrorMessage的宏。

宏定义冲突

我们怀疑开发者在他们的项目中其他地方有一个名为ErrorMessage的宏,这与方法名称发生了冲突。在客户的帮助下,我们找到了它:

// Produces the error text for an HRESULT.
struct ErrorMessageString
{
    ErrorMessageString(HRESULT hr);
    operator PCWSTR() { return (PCWSTR)m_errorMessage; }
    CStringW m_errorMessage;
};

#define ErrorMessage(hr) ((PCWSTR)ErrorMessageString(hr))

宏的工作原理

ErrorMessage宏创建了一个ErrorMessageString对象,其构造函数查找与提供的HRESULT相关联的错误消息字符串,然后强制它产生一个字符串指针。显然,它的预期用途是这样的:

LogMessage(L"Problem toggling the widget", ErrorMessage(hr));

宏没有边界意识。C++/WinRT头文件试图声明一个名为ErrorMessage()的方法,而宏介入并说“我会处理那个!”然后它看到代码没有提供参数,但宏需要一个参数,所以你得到了“参数不足”的错误。然后编译器耸耸肩说,“好吧,我会替换它”,你最终得到的是:

template <typename D>
struct consume_Windows_UI_Xaml_IExceptionRoutedEventArgs
{
    [[nodiscard]] auto ((PCWSTR)ErrorMessageString()) const;
};

这是无意义的,一连串的错误消息告诉你这是多么的无意义。

解决方案

一个解决方案是在包含问题头文件时移除宏。

#pragma push_macro("ErrorMessage")
#undef ErrorMessage
#pragma push_macro("GetCurrentTime")
#undef GetCurrentTime
#pragma push_macro("TRY")
#undef TRY
#include <winrt/Windows.UI.Xaml.h>
[ other C++/WinRT headers ... ]
#pragma pop_macro("TRY")
#pragma pop_macro("GetCurrentTime")
#pragma pop_macro("ErrorMessage")

我预先添加了GetCurrentTime和TRY,因为你很快就会遇到那个问题,所以我们现在就解决它。

更好的解决方案

更好的解决方案是简单地去掉宏。

// Don't use this. It returns a dangling pointer.
inline PCWSTR ErrorMessage(HRESULT hr) { return (PCWSTR)ErrorMessageString(hr); }

通过这个例子,我们可以看到,理解编译器错误并找到问题的根源是非常重要的。宏定义的冲突是C++编程中常见的问题之一,了解如何避免和解决这些问题,将有助于我们写出更健壮的代码。

科技脉搏,每日跳动。

与敖行客 Allthinker一起,创造属于开发者的多彩世界。

- 智慧链接 思想协作 -

Tags:

最近发表
标签列表