C++ 调用约定

2024 年 8 月 28 日 | 阅读 9 分钟

在 C++ 中,约定指的是编写代码时遵循的标准规则和指南。

这些约定可以涵盖广泛的主题,包括

1. 命名约定

这是为代码中的变量、函数和其他标识符命名的规则。例如,变量名通常使用 camelCase,函数名使用 PascalCase

C++ 代码

输出

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

说明

在此示例中,常量用大写字母和下划线表示,变量用 camelCase 表示,函数用 PascalCase 表示。此外,循环中使用的变量通常用缩写形式表示。这些约定并非严格必需,但在 C++ 社区中被广泛遵循,有助于使您的代码更具可读性,更易于理解。

2. 代码布局约定

这是用于格式化和组织代码的规则。例如,许多程序员使用缩进来指示代码的块结构,并使用空格来分隔不同的元素。

C++ 代码

输出

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

说明

在此示例中,使用缩进来指示代码的块结构,并使用空格来分隔不同的元素。这些约定有助于提高代码的可读性和易理解性。还有许多其他代码布局约定可供您遵循,例如使用空行来分隔代码的不同部分,以及使用注释来提供额外的上下文和文档。通过遵循这些约定,您可以使您的代码更加一致,更易于使用。

3. 注释约定

这是用于在代码中编写注释的规则。注释可以帮助解释代码块的用途或为函数提供文档。

C++ 代码

输出

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

说明

在此示例中,使用注释来提供代码的额外上下文和解释。例如,使用注释来解释将数组初始化为 0 的循环的用途,以及使用另一注释来解释打印数组元素的循环的用途。

注释约定可能有所不同,但通常在代码中包含注释以帮助解释其用途并提供额外上下文是一个好习惯。这可以使您的代码更容易理解和维护。

4. 文档约定

这是用于为代码编写文档的规则,例如 API 文档或类文档。

C++ 代码

输出

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

说明

在此示例中,在文件开头以及 main 函数上方提供了文档。文件文档包含有关程序用途、作者和日期等信息。函数文档包含有关 main 函数的用途和返回值的信息。文档约定可能有所不同,但通常在代码中包含文档以帮助解释其用途并提供额外上下文是一个好习惯。这可以使您的代码更容易理解和维护。

通过遵循约定,您可以使您的代码更容易被其他程序员阅读和理解。它还可以帮助确保您的代码一致并遵循最佳实践。

5. 调用约定

在 C++ 中,调用约定是一组规则,用于确定如何将函数参数传递给函数以及如何将返回值传递回调用者。调用约定用于确保函数在不同平台和编译器上都能被正确一致地调用。

C++ 中常用的调用约定有几种,包括

__cdecl: 这是大多数平台上 C++ 的默认调用约定。它是一种“干净”的调用约定,不使用任何特殊指令或寄存器来传递函数参数或返回值。相反,它依赖堆栈来传递参数,并依赖 EAX 寄存器来返回值。

__stdcall: 此调用约定用于按名称调用的函数。它类似于 __cdecl,但调用者负责在函数返回后清理堆栈。

__fastcall: 此调用约定用于通过在寄存器(ECX 和 EDX)中传递前两个参数来优化函数调用。它比 __cdecl 或 __stdcall 更快,但灵活性较低,因为它只能在寄存器中传递有限数量的参数。

__thiscall: 此调用约定用于 C++ 类中的成员函数。它类似于 __fastcall,但 this 指针在 ECX 寄存器中传递。

您可以使用函数属性为 C++ 中的函数指定特定的调用约定。例如

C++ 代码

说明

在此示例中,使用不同的调用约定声明了三个函数:__cdecl、__stdcall 和 __fastcall。main 函数使用指定的调用约定调用这些函数。

使用正确的函数调用约定非常重要,以确保其正确调用并避免堆栈损坏或返回值不正确等问题。

您可以使用函数属性为 C++ 中的函数指定特定的调用约定。例如

语法-1

或者,您可以使用 #pragma 指令为模块中的所有函数指定调用约定

语法-2

在 C++ 中使用调用约定的优点

在 C++ 中使用调用约定有几个优点

兼容性:不同的平台和编译器可能对如何传递函数参数和返回值有不同的要求。通过使用特定的调用约定,您可以确保您的代码与不同的平台和编译器兼容。

一致性:使用一致的调用约定有助于确保您的代码易于阅读和理解,尤其是在团队合作或您的代码将供他人使用时。

优化:某些调用约定比其他约定更有效。例如,__fastcall 调用约定比 __cdecl 或 __stdcall 更快,因为它使用寄存器来传递函数参数。这对于频繁调用的函数特别有用。

安全性:使用一致的调用约定有助于防止堆栈损坏或返回值不正确等错误。例如,__stdcall 调用约定确保调用者负责在函数返回后清理堆栈,这有助于防止堆栈损坏。

总而言之,使用调用约定可以使您的代码更具兼容性、一致性、效率和安全性。

在 C++ 中使用调用约定的缺点

在 C++ 中使用调用约定存在一些潜在的缺点

复杂性:使用不同的调用约定会增加代码的复杂性,尤其是在处理具有许多不同函数的庞大项目时。这会使您的代码更难理解和维护。

兼容性问题:如果您使用的调用约定不受特定平台或编译器的支持,您可能需要修改代码或使用其他调用约定。这可能非常耗时,并且可能需要额外的测试才能确保您的代码仍然正确。

性能开销:某些调用约定可能会引入少量性能开销,尤其是在它们需要额外的指令或寄存器使用时。对于大多数应用程序来说,这可能并不重要,但对于高性能代码来说,这是一个需要考虑的因素。

可移植性:如果您使用的调用约定特定于某个平台或编译器,那么您的代码可能无法移植到其他平台或编译器。如果您想在不同平台上重用代码或在混合环境中工作,这可能会成为一个问题。

总而言之,与优点相比,使用调用约定的缺点通常较小,但在决定为代码使用哪种调用约定时尚,考虑这些缺点很重要。


下一个主题C++ 中的 HASHSET