网站的备案手续,网站建设所需要的技术,网站建设推广公司,网站搭建报价视频参考:https://www.bilibili.com/video/BV1mEUCY8EiC/
这些字幕讨论了编译器警告的概念以及如何在编译过程中启用和处理警告。以下是字幕的内容摘要#xff1a; 警告的定义#xff1a;警告是编译器用来告诉你某些地方可能存在问题#xff0c;尽管编译器不强制要求你修复…视频参考:https://www.bilibili.com/video/BV1mEUCY8EiC/
这些字幕讨论了编译器警告的概念以及如何在编译过程中启用和处理警告。以下是字幕的内容摘要 警告的定义警告是编译器用来告诉你某些地方可能存在问题尽管编译器不强制要求你修复它们。警告并不会阻止编译过程但它们通常提示代码中可能存在潜在问题。 警告级别警告通常分为不同的级别例如1级、2级、3级、4级等。你可以选择启用一个警告级别以便只关注特定类型的警告而不是每一个单独的警告。 启用警告作者提到通过启用较高级别的警告可以让编译器显示更多的警告信息帮助开发者发现潜在问题。 解决警告一些警告是可以修复的而其他警告则可能是由于外部库或系统文件如 windows.h引起的在这些情况下可能无法轻易修复。 警告级别的调整如果某些警告级别的警告过于繁琐可以通过降低警告级别来减少警告的数量从而使得编译过程更加顺利。 具体示例提到了一些警告信息例如编译器告诉开发者结构体中可能插入了填充或者警告与 Windows 头文件相关的问题。
总结起来这段对话讨论了编译器警告的启用、调整和处理策略帮助开发者理解如何更有效地管理编译时的警告信息。
在MSVCMicrosoft Visual C中警告级别用于控制编译器输出的警告信息的详细程度。MSVC提供了四个警告级别分别为
级别 0 (/W0)关闭所有警告。适用于不希望看到任何警告的情况但不建议在开发中使用因为可能会错过重要的提示。级别 1 (/W1)显示最低级别的警告。适用于仅查看最严重警告的情况。级别 2 (/W2)显示常见的警告信息通常是开发过程中需要注意的警告。级别 3 (/W3)显示更多警告信息是默认的警告级别。适用于大多数开发场景。级别 4 (/W4)显示所有警告包括那些可能无关紧要的。适用于希望尽可能详细地查看警告信息的情况。级别 5 (/Wall)显示所有警告包括非常详细的信息。用于调试时极为详尽的检查。
cmake 中添加警告参数
# 为 MSVC 编译器添加参数
if(MSVC) # 如果编译器是 MSVCMicrosoft Visual C# 设置 C 编译选项set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} /WX /W4 /wd4819)# /WX : 将所有警告视为错误会让编译因警告失败# /W4 : 设置警告级别为 4显示大多数警告# /wd4819 : 屏蔽警告 C4819避免文件编码问题导致的警告
endif()下面是解决相关的警告
C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp
[build] cl: 命令行 warning D9025 :正在重写“/W3”(用“/W4”)
[build] C:\Users\16956\Documents\game\day16\game\game\game.h(134): error C2220: 以下警告被视为错误
[build] C:\Users\16956\Documents\game\day16\game\game\game.h(134): warning C4201: 使用了非标准扩展: 无名称的结构/联合
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(110): warning C4244: “参数”: 从“uint64”转换到“DWORD”可能丢失数据
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(27): warning C4244: “初始化”: 从“int”转换到“uint8”可能丢失数据
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(28): warning C4244: “初始化”: 从“int”转换到“uint8”可能丢失数据
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(161): warning C4100: “pState”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(161): warning C4100: “dwUserIndex”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(167): warning C4100: “pVibration”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(167): warning C4100: “dwUserIndex”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Height”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Width”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Y”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(382): warning C4100: “X”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(573): warning C4100: “cmdshow”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(573): warning C4100: “cmdline”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(572): warning C4100: “hInstPrev”: 未引用的形参
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(619): warning C4189: “xOffset”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(620): warning C4189: “yOffset”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(878): warning C4189: “MillisecondPerFrame”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(892): warning C4189: “Temp”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(881): warning C4189: “FPS”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(882): warning C4189: “MCPF”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(725): warning C4189: “Left”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(724): warning C4189: “Down”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(726): warning C4189: “Right”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(723): warning C4189: “Up”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(35): warning C4505: “GameStartup”: 已删除具有内部链接的未引用函数
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(45): warning C4505: “GameShutDown”: 已删除具有内部链接的未引用函数
[build] ninja: build stopped: subcommand failed.[build] C:\Users\16956\Documents\game\day16\game\game\game.h(134): warning C4201: 使用了非标准扩展: 无名称的结构/联合 warning C4201 是 MSVC 中的一个警告它提示你使用了非标准扩展无名称的结构或联合。这意味着在你的代码中你定义了一个没有名称的匿名结构体或联合体。
IDE 显示的是一个插件 解决上面的警告 问题出现在 union 内部的结构体部分
union {game_button_state Button[6]; // 按钮状态最多 6 个按钮struct {game_button_state Up; // 上方向键状态game_button_state Down; // 下方向键状态game_button_state Left; // 左方向键状态game_button_state Right; // 右方向键状态game_button_state LeftShoulder; // 左肩键状态game_button_state RightShoulder; // 右肩键状态};
};这里struct 是一个匿名结构体没有给它命名。因此这会触发 warning C4201因为这种匿名结构体的使用违反了标准的 C 规则虽然 MSVC 允许它作为扩展。
如何理解这个警告
C 标准要求结构体或联合体应当具备一个名字便于在后续的代码中引用。匿名结构体或联合体虽然在某些编译器中被允许但它们并不符合标准因此会触发 C4201 警告。
如何解决
要解决这个问题你需要给匿名的结构体命名。可以通过以下方式修改你的代码
union {game_button_state Button[6]; // 按钮状态最多 6 个按钮struct game_controller_buttons {game_button_state Up; // 上方向键状态game_button_state Down; // 下方向键状态game_button_state Left; // 左方向键状态game_button_state Right; // 右方向键状态game_button_state LeftShoulder; // 左肩键状态game_button_state RightShoulder; // 右肩键状态};
};在上面的代码中game_controller_buttons 是给结构体命名的名称这样就不会触发 C4201 警告了。
总结
warning C4201 提示你在代码中使用了匿名结构体或联合体这可能是编译器的扩展功能但不符合 C 标准。通过为结构体或联合体命名可以解决这个警告。
这个警告我们不认为是一个错误
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} /WX /W4 /wd4819 /wdc4201”)
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(110): warning C4244: “参数”: 从“uint64”转换到“DWORD”可能丢失数据
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(27): warning C4244: “初始化”: 从“int”转换到“uint8”可能丢失数据 [build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(28): warning C4244: “初始化”: 从“int”转换到“uint8”可能丢失数据
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(161): warning C4100: “pState”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(161): warning C4100: “dwUserIndex”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(167): warning C4100: “pVibration”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(167): warning C4100: “dwUserIndex”: 未引用的形参 warning C4100 是 MSVC 的一个警告表明某个函数参数未被使用。在你的代码中这些未使用的参数是 pState、pVibration 和 dwUserIndex它们出现在以下打桩函数中
X_INPUT_GET_STATE(XInputGetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}X_INPUT_SET_STATE(XInputSetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}由于打桩函数的实现仅返回 ERROR_DEVICE_NOT_CONNECTED而没有使用这些参数因此触发了 C4100 警告。
解决方法
有几种方法可以消除这个警告 方法 1显式地标记未使用的参数
可以通过显式引用参数来避免警告即使没有实际使用它们
X_INPUT_GET_STATE(XInputGetStateStub) { (void)dwUserIndex; // 明确声明未使用(void)pState; // 明确声明未使用return (ERROR_DEVICE_NOT_CONNECTED);
}X_INPUT_SET_STATE(XInputSetStateStub) { (void)dwUserIndex; // 明确声明未使用(void)pVibration; // 明确声明未使用return (ERROR_DEVICE_NOT_CONNECTED);
}这种方式简单直接表明你有意不使用这些参数。 方法 2使用 MSVC 特定的宏
MSVC 提供了一个 UNREFERENCED_PARAMETER 宏可以标记未使用的参数。它会自动消除警告
#include windows.h // 包含 UNREFERENCED_PARAMETER 宏X_INPUT_GET_STATE(XInputGetStateStub) { UNREFERENCED_PARAMETER(dwUserIndex);UNREFERENCED_PARAMETER(pState);return (ERROR_DEVICE_NOT_CONNECTED);
}X_INPUT_SET_STATE(XInputSetStateStub) { UNREFERENCED_PARAMETER(dwUserIndex);UNREFERENCED_PARAMETER(pVibration);return (ERROR_DEVICE_NOT_CONNECTED);
}方法 3修改函数签名
如果这些参数完全无用仅用于符合接口定义可以使用未命名的参数形式
X_INPUT_GET_STATE(XInputGetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}X_INPUT_SET_STATE(XInputSetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}然而如果这些参数在其他上下文中需要使用不推荐这种方式。 方法 4全局屏蔽警告
如果这些警告在项目中普遍存在也可以在编译器选项或代码中禁用 C4100 警告 CMake 中添加编译选项 if(MSVC)add_compile_options(/wd4100) # 禁用 C4100 警告
endif()在代码中使用 #pragma #pragma warning(push)
#pragma warning(disable: 4100)X_INPUT_GET_STATE(XInputGetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}X_INPUT_SET_STATE(XInputSetStateStub) { return (ERROR_DEVICE_NOT_CONNECTED);
}#pragma warning(pop)总结
推荐优先使用 方法 1 或 方法 2显式标记未使用的参数既解决了警告也保留了代码的可读性。如果打桩函数广泛使用且参数确实无用可以考虑 方法 4 全局屏蔽。
c 属性
在 C 中除了使用编译器特定的宏如 MSVC 的 UNREFERENCED_PARAMETER还可以利用标准或扩展的函数属性来表明某个参数未被使用从而避免警告。以下是常见的实现方式 1. 使用 C17 的 [[maybe_unused]] 属性
从 C17 开始标准引入了 [[maybe_unused]] 属性用于标记未被使用的变量或参数。这样可以告诉编译器此参数未被使用是有意的不需要警告。
X_INPUT_GET_STATE(XInputGetStateStub) {[[maybe_unused]] DWORD dwUserIndex; // 参数标记为未使用[[maybe_unused]] XINPUT_STATE* pState;return (ERROR_DEVICE_NOT_CONNECTED);
}也可以直接在参数列表中使用
X_INPUT_GET_STATE(XInputGetStateStub([[maybe_unused]] DWORD dwUserIndex, [[maybe_unused]] XINPUT_STATE* pState)) {return (ERROR_DEVICE_NOT_CONNECTED);
}优点标准化跨编译器支持。缺点需要使用 C17 或更新版本。 2. 使用编译器特定的属性
不同编译器提供了自己的方式来标记未使用的参数
(a) GCC 和 Clang: __attribute__((unused))
适用于 GCC 和 Clang可以通过 __attribute__((unused)) 标记参数
X_INPUT_GET_STATE(XInputGetStateStub(DWORD __attribute__((unused)) dwUserIndex, XINPUT_STATE* __attribute__((unused)) pState)) {return (ERROR_DEVICE_NOT_CONNECTED);
}或者用在局部变量上
X_INPUT_GET_STATE(XInputGetStateStub) {DWORD dwUserIndex __attribute__((unused));XINPUT_STATE* pState __attribute__((unused));return (ERROR_DEVICE_NOT_CONNECTED);
}(b) MSVC: __pragma(warning(suppress: 4100))
MSVC 提供了特定的 __pragma 语法来抑制特定警告
X_INPUT_GET_STATE(XInputGetStateStub) { __pragma(warning(suppress: 4100)) DWORD dwUserIndex;__pragma(warning(suppress: 4100)) XINPUT_STATE* pState;return (ERROR_DEVICE_NOT_CONNECTED);
}3. 使用通用技巧
如果无法使用上述属性可以使用一些编程技巧告诉编译器这是有意未使用的参数
(a) 强制类型转换
通过将参数强制转换为 void可以消除未使用参数的警告
X_INPUT_GET_STATE(XInputGetStateStub) {(void)dwUserIndex; // 明确声明未使用(void)pState; // 明确声明未使用return (ERROR_DEVICE_NOT_CONNECTED);
}(b) 使用 [[nodiscard]] 配合
对于返回值函数可以结合 [[nodiscard]] 属性强调参数未被使用但函数仍需要处理。 总结
如果项目使用 C17 或更新版本优先使用 [[maybe_unused]]这是标准化的方式。如果需要支持 旧版本编译器 GCC/Clang使用 __attribute__((unused))。MSVC使用 __pragma 或 UNREFERENCED_PARAMETER 宏。 若无需依赖编译器特性可使用 (void) 转换法这是一种跨平台兼容的解决方案。
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Height”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Width”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(383): warning C4100: “Y”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(382): warning C4100: “X”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(573): warning C4100: “cmdshow”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(573): warning C4100: “cmdline”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(572): warning C4100: “hInstPrev”: 未引用的形参 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(619): warning C4189: “xOffset”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(620): warning C4189: “yOffset”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(878): warning C4189: “MillisecondPerFrame”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(892): warning C4189: “Temp”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(881): warning C4189: “FPS”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(882): warning C4189: “MCPF”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(725): warning C4189: “Left”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(724): warning C4189: “Down”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(726): warning C4189: “Right”: 局部变量已初始化但不引用 [build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(723): warning C4189: “Up”: 局部变量已初始化但不引用
[build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(35): warning C4505: “GameStartup”: 已删除具有内部链接的未引用函数 [build] C:\Users\16956\Documents\game\day16\game\game\game.cpp(45): warning C4505: “GameShutDown”: 已删除具有内部链接的未引用函数
[build] C:\Users\16956\Documents\game\day16\game\game\win32_game.cpp(844) : warning C4701: 使用了可能未初始化的局部变量“ByteToLock”
14:10 常用使用的其他命令行选项 在 Visual Studio 中-FC 和 -Zi 是用于编译器的两个选项分别用于控制文件路径的显示和调试信息的生成。
-FC 参数
全称Full Path to Source Code Files
作用启用此选项后编译器在生成的调试信息中会记录源代码文件的完整路径而不仅仅是文件名。用途 在调试或错误日志中完整路径有助于区分同名但位于不同目录的文件。对于大型项目或涉及多层文件夹的项目使用 -FC 可以减少文件路径冲突引起的歧义。
-Zi 参数
全称Generate Program Database for Debugging
作用启用此选项后编译器会生成包含详细调试信息的 PDBProgram Database文件。用途 使调试工具如 Visual Studio 调试器能够通过 PDB 文件查看代码中的变量、函数、调用堆栈等信息。是调试模式下的默认配置用于支持断点调试、单步执行和查看源代码。
综合使用
-FC 通常与 -Zi 一起使用尤其在调试场景中
完整路径-FC有助于清楚地定位源代码文件。调试信息-Zi提供详细的调试能力。
示例
如果你在 VS 中手动编译代码可以添加如下命令
cl -Zi -FC source.cpp这将生成包含完整路径的调试信息文件.pdb 文件。
在 Visual Studio 的编译器中-Oi 是一个优化选项用于启用 内联函数调用提高程序的性能。 作用
-Oi 参数启用编译器对特定内建函数intrinsic functions的内联替换。
内建函数Intrinsic Functions是编译器提供的一些特殊函数通常映射到特定的 CPU 指令。例如memcpy、strcmp 或数学函数如 sqrt。启用 -Oi 后这些函数在编译时被替换为等效的高效汇编指令而不是通过函数调用完成任务。 优点
性能提升 减少函数调用的开销如栈操作和返回值处理。提高执行效率因为直接使用了 CPU 指令。 优化代码大小 内联代码有时能减少代码膨胀尤其是对于小函数。 使用高级指令 编译器可能使用更高效的 CPU 指令来实现特定功能。 可能的缺点
代码大小增加 如果过多的函数被内联可能导致生成的代码体积增大。 兼容性问题 某些内建函数可能与特定硬件架构相关因此需要确保目标硬件支持。 调试复杂性 内联后的代码可能难以逐步调试因为它不再是显式的函数调用。 使用场景
适用高性能应用尤其是对数学计算、字符串操作等性能敏感的场景。不适用代码大小有限制或者需要清晰的调试信息时。 相关指令
-Oi 通常与其他优化选项结合使用
-O2最大化优化性能包括 -Oi。-Ox极致优化也启用 -Oi。-Ob控制内联的函数数量。 示例
编译命令
cl -Oi source.cpp代码示例
编译器可能将以下代码
#include math.hdouble square_root(double x) {return sqrt(x);
}转为内联的汇编指令而不是调用标准库函数 sqrt。 总结使用 -Oi 能提升性能但需根据项目需求权衡性能与代码体积之间的关系。
在 Visual Studio 编译器中-GR- 和 -EHa- 是控制运行时功能和异常处理机制的选项它们的作用如下 -GR- 参数
作用禁用 RTTIRun-Time Type Information。
RTTI 简介
RTTI 是 C 提供的一种运行时机制允许程序在运行时动态查询对象的类型信息例如使用 typeid 和 dynamic_cast。启用 RTTI默认设置-GR会在程序中生成额外的类型信息。
禁用 RTTI 的效果
减少代码大小避免生成额外的类型信息可以降低可执行文件的体积。提升性能避免运行时类型检查带来的额外开销。限制功能typeid 和 dynamic_cast 无法使用程序中尝试调用它们会导致编译错误。
使用场景
适用于不依赖 RTTI 的代码尤其是性能和代码大小敏感的项目例如嵌入式开发。代码完全避免了多态和运行时类型查询。 -EHa- 参数
作用禁用对结构化异常处理SEH和 C 异常的支持。
SEH 和 C 异常简介
SEHWindows 特有的异常机制捕获系统级异常如访问冲突。C 异常C 标准支持的异常机制try-catch 块。
禁用异常支持的效果
减少代码大小禁用异常后程序不需要生成额外的异常处理表。提升性能减少异常支持相关的运行时检查。限制功能所有 try-catch 块、throw 表达式以及捕获系统异常的能力都不可用。
风险
禁用异常后程序中发生未捕获的错误将直接导致崩溃。开发者需要依赖其他方式如错误码来处理异常情况。
使用场景
适合不依赖异常处理的小型项目或性能敏感的嵌入式系统。项目中已经采用其他机制如返回值或状态码代替异常处理。 两者对比与结合
参数功能适用场景限制-GR-禁用 RTTI减少运行时类型信息性能优化或不使用动态类型查询时禁用 typeid 和 dynamic_cast-EHa-禁用 C 异常和 SEH减少异常支持开销不依赖异常处理的性能优化场景无法使用 try-catch 和异常机制
结合使用
-GR- -EHa- 通常在对性能和代码大小极为敏感的项目中一起使用例如嵌入式开发或实时系统。 示例
编译命令
cl -GR- -EHa- source.cpp代码限制示例
以下代码在启用 -GR- 和 -EHa- 后会导致编译错误
#include iostream
#include typeinfoclass Base { virtual void func() {} };
class Derived : public Base {};int main() {try {throw std::runtime_error(Error); // 会报错} catch (...) {std::cout Caught an exception\n;}Base* b new Derived();if (typeid(*b) typeid(Derived)) { // 会报错std::cout Derived type\n;}return 0;
}编译器反馈
禁用 RTTI 后typeid 和 dynamic_cast 的使用会报错。禁用异常后try-catch 和 throw 的使用会报错。 总结
-GR-禁用运行时类型信息优化性能和减小代码体积。-EHa-禁用异常处理支持进一步减少代码开销但需要谨慎处理错误情况。两者结合适用于不需要运行时类型检查和异常支持的高性能或嵌入式项目。 -EHa-我貌似不会报错不知道为啥
# 为 MSVC 编译器添加参数
if(MSVC) # 如果编译器是 MSVCMicrosoft Visual C# 设置 C 编译选项set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -GR- -EHa- /WX /W4 /wd4819 /wd4201 /Z7 /FC)# /WX : 将所有警告视为错误会让编译因警告失败# /W4 : 设置警告级别为 4显示大多数警告# /wd4819 : 屏蔽警告 C4819避免文件编码问题导致的警告
endif()在编译和链接程序时/link 选项是用于 Microsoft Visual CMSVC编译器 的一个特殊选项主要用来向链接器传递参数。它通常用于在命令行中将编译器选项与链接器选项分开。
使用场景
/link 后面跟随的是直接传递给链接器的参数而不是编译器的选项。通过这种方式可以在一次命令中同时指定编译器和链接器的设置。
示例
cl main.cpp /link /OUT:myprogram.execl: MSVC 的编译器工具。main.cpp: 源代码文件。/link: 告诉编译器接下来的参数是链接器选项。/OUT:myprogram.exe: 链接器选项用于指定生成的可执行文件名称。 常见的链接器选项
以下是一些可以与 /link 一起使用的链接器选项
/OUT:filename: 指定输出文件名称。/LIBPATH:path: 指定搜索库的路径。/SUBSYSTEM:type: 指定子系统类型如 CONSOLE 或 WINDOWS。/DEBUG: 启用调试信息。/ENTRY:function: 指定程序入口点。 注意事项
顺序: /link 后的参数会直接传递给链接器因此它必须位于链接器选项之前。用途: /link 一般在需要自定义链接行为或指定复杂链接器选项时使用。 /MD 和 /MT 都是 Microsoft Visual C 编译器的选项用于指定运行时库的链接方式。它们的区别在于使用的是 动态链接库DLL还是 静态链接库.lib。这两个选项控制如何处理 C 标准库和 C 运行时库的链接。
/MD - 动态链接运行时库DLL
解释使用 动态链接库DLL来链接 C 运行时库和 C 标准库。行为编译器会链接到动态运行时库 msvcrt.dllMicrosoft C Runtime Library。这意味着你的程序在运行时需要依赖于外部的动态链接库文件。优点生成的可执行文件较小因为运行时库被共享可以由多个程序同时使用。缺点在程序运行时需要确保目标系统上已经安装了相应版本的 DLL 文件否则程序将无法启动。
/MT - 静态链接运行时库静态库
解释使用 静态链接库 来链接 C 运行时库和 C 标准库。行为编译器会将运行时库和 C 标准库的代码直接嵌入到可执行文件中。这样你的程序不需要依赖于任何外部动态链接库。优点生成的可执行文件完全独立不依赖任何外部的 DLL 文件这对于某些环境如嵌入式系统或需要部署独立程序的场景是有利的。缺点可执行文件会更大因为运行时库的所有代码都被静态地链接进去了。此外不同程序之间无法共享运行时库因此如果多个程序使用相同的静态库会导致冗余代码。
/MDd 和 /MTd调试版本
/MDd动态链接调试版本的运行时库DLL通常用于调试模式。/MTd静态链接调试版本的运行时库静态库通常用于调试模式。
总结
/MD动态链接运行时库程序运行时依赖 msvcrt.dll适用于需要共享运行时库的场景。/MT静态链接运行时库程序包含所有运行时库的代码适用于希望程序完全独立的场景。
选择哪一个取决于项目的需求
如果需要减小程序大小并共享库使用 /MD。如果需要完全独立的程序且不依赖于外部 DLL 文件使用 /MT。
-Gm- 是 Microsoft Visual C 编译器的一个选项用于控制 生成程序的最小调试信息。
解释
-Gm- 禁用最小调试信息的生成。默认情况下编译器会生成较为详细的调试信息以便调试工具如 Visual Studio 调试器能够提供更全面的调试支持。使用 -Gm- 后编译器会关闭这种调试信息生成但它不会完全禁用所有调试信息只是减少生成的调试信息量。
使用场景
减少调试信息大小在某些情况下你可能希望生成较小的调试信息文件以减小程序的尺寸尤其是在发布版本中。优化编译速度禁用最小调试信息可能会略微提高编译速度尤其是在大型项目中。
对比其他调试选项
-Gm启用最小调试信息生成较少的调试信息主要用于优化构建过程。-Zi生成完整的调试信息通常用于调试版本的构建。-Z7生成最小调试信息通常适用于调试工具如在没有完整源代码时进行基本的调试。
总结
-Gm- 选项用于禁用最小调试信息的生成在某些情况下可以减少调试信息的体积但通常不推荐用于需要调试的场合。 在使用 -Fm 选项生成 .map 文件时符号名称如函数名、变量名会被编译器名称修饰名称改编或 mangling。这是因为 C 编译器需要通过对符号名称进行修饰来支持函数重载、模板等特性。
1. C 符号名称修饰的原因
C 是一种支持函数重载、模板和命名空间的语言。这意味着同一函数名可能会在不同的上下文中定义多个版本。例如
同名函数的不同参数类型函数重载。模板类或函数的实例化泛型编程。
为了区分这些函数或变量编译器会对它们的名称进行修饰mangling即将函数名或变量名与其类型信息、模板参数等信息结合起来形成唯一的标识符。
2. 符号名称修饰的表现
在 .map 文件中你会看到原本简单的函数名或变量名被改为一长串看似无意义的字符。这些字符是由编译器根据函数的参数类型、返回类型、命名空间等信息生成的目的是避免不同的符号冲突。
例如
一个简单的函数 int add(int, int) 在 .map 文件中的名称可能会变成 _Z3addiij其中 _Z3add 表示函数名ii 表示两个 int 类型的参数j 表示返回值类型。
3. 修饰后的符号名称的含义
_Z标志名称是经过修饰的由 C 编译器生成。函数名和类型信息修饰符中包含函数名以及参数的类型和顺序甚至返回值的类型。
4. 如何避免名称修饰
如果你不希望看到这些修饰的符号名称可以考虑使用 extern C 来避免 C 的名称修饰。extern C 告诉编译器按 C 语言规则进行符号命名不进行修饰。
例如
extern C {int add(int a, int b) {return a b;}
}这种方式下add 函数在 .map 文件中的名称将是 add而不是修饰后的名称。
结论
在使用 -Fm 选项生成 .map 文件时符号名称被修饰是因为 C 编译器通过名称修饰来支持函数重载、模板、命名空间等特性。如果需要避免这种修饰可以使用 extern C 来禁止名称修饰。
/Od 是 Microsoft Visual C 编译器的一个选项用于禁用优化。
作用
/Od 表示 禁用所有优化Disable optimization即编译器不会进行任何优化操作包括常见的如代码内联、循环展开、死代码删除等。这个选项通常用于调试时以便让调试信息更准确程序的行为更接近源代码的编写方式。禁用优化后编译器不会对代码进行任何修改便于开发者更容易地跟踪和调试程序的执行流程。
使用场景
调试阶段在调试程序时禁用优化可以避免优化所带来的副作用如变量的值被编译器优化掉、函数调用被内联等使得调试时的行为和源代码一致。排查问题在排查程序错误时禁用优化有助于确认程序的实际行为因为优化可能会改变代码的执行顺序或变量的生命周期。
示例
cl /Od myprogram.cpp这个命令会编译 myprogram.cpp并禁用所有优化。
总结
/Od 选项用于禁用编译器的优化通常在调试过程中使用以确保调试信息与源代码更一致。
开始将键盘输入移到与平台无关的代码中