网站首页 > 技术文章 正文
在软件开发的过程中,我们经常会遇到各种编译器错误。这些错误有时让人摸不着头脑,但它们实际上是编译器试图告诉我们代码中存在的问题。今天,我们将通过一个具体的例子,探讨如何理解和解决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++常见面试题的分析与解答
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)