网站首页 > 技术文章 正文
在软件开发的过程中,我们经常会遇到各种编译器错误。这些错误有时让人摸不着头脑,但它们实际上是编译器试图告诉我们代码中存在的问题。今天,我们将通过一个具体的例子,探讨如何理解和解决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一起,创造属于开发者的多彩世界。
- 智慧链接 思想协作 -
猜你喜欢
- 2025-01-20 C++|类型转换与运行时类型安全检查
- 2025-01-20 C++Qt开发——事件处理函数
- 2025-01-20 百度Linux C++后台开发面试题(个人整理)
- 2025-01-20 怎样才算学会了C++基础,一篇文章学习了解(包含Qt内容)
- 2025-01-20 C++通过aidl与Android系统服务通信(一)
- 2025-01-20 朝文分享(54):深入C++(二十一)——多态
- 2025-01-20 c++多态
- 2025-01-20 深入探讨C++多线程性能优化
- 2025-01-20 【C++】C++ 11 新特性:使用示例
- 2025-01-20 避免踩坑,C++常见面试题的分析与解答
- 1507℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 510℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 487℃MySQL service启动脚本浅析(r12笔记第59天)
- 467℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 465℃启用MySQL查询缓存(mysql8.0查询缓存)
- 445℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 424℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 421℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)