C++ 中的变量命名约定

Variable Naming Conventions in C++

提问人: 提问时间:10/25/2008 最后编辑:stung 更新时间:9/10/2019 访问量:87547

问:

我来自.NET世界,我是编写C++的新手。我只是想知道在命名局部变量和结构成员时,首选的命名约定是什么。

例如,我继承的遗留代码有很多这样的内容:

struct MyStruct
{
   TCHAR           szMyChar[STRING_SIZE];
   bool            bMyBool;
   unsigned long   ulMyLong;
   void*           pMyPointer;
   MyObject**      ppMyObjects;
}

我来自 C# 背景,看到带有匈牙利符号的变量时,我感到很震惊(我第一次看到它时,我忍不住笑了 pp 前缀)。

我宁愿以这种方式命名我的变量(尽管我不确定将第一个字母大写是否是一种好约定。我见过其他方法(见下面的链接)):

struct MyStruct
{
   TCHAR           MyChar[STRING_SIZE];
   bool            MyBool;
   unsigned long   MyLong;
   void*           MyPointer;
   MyObject**      MyObjects;
}

我的问题是:这(前一种方式)仍然是在 C++ 中命名变量的首选方式吗?

引用:

http://geosoft.no/development/cppstyle.html

http://www.syntext.com/books/syntext-cpp-conventions.htm

http://ootips.org/hungarian-notation.html

谢谢!

C++ 变量 命名约定

评论


答:

1赞 Leon Timmermans #1

匈牙利语表示法在 Win32 和 MFC API 的用户中很常见。如果你的前辈正在使用它,你最好继续使用它(即使它很糟糕)。C++ 世界的其他部分从未有过这种脑死亡约定,所以如果你使用的是这些 API 以外的东西,请不要使用它。

评论

1赞 John D. Cook 10/25/2008
匈牙利语表示法在 MFC 中最为复杂,但C++世界的其他地区使用这种表示法的最小子集,例如 m_ 表示“member”,p 表示“指针”。
65赞 Head Geek 10/25/2008 #2

这种匈牙利符号是相当无用的,如果你必须改变某样东西的类型,可能比无用更糟糕。(正确的匈牙利符号是另一回事。

我建议你使用你的团队所做的任何事情。如果您是唯一参与该计划的人,请以对您最有意义的方式命名它们。

评论

13赞 Édouard Lopez 3/23/2016
你的第二句话是完全错误的,你永远不应该用这种座右铭来发展。你永远不知道谁会在你之后从事这个项目。你的命名应该使你的代码对你、你的未来——你和其他人都是明确的。变量/函数名称应该有助于理解正在发生的事情。
5赞 Head Geek 3/24/2016
这方面是错误的?以一种对你有意义的方式命名变量就是让你的代码对你未来的自己明确,如果你有任何编码经验的话。
1赞 Rob Prouse #3

我认为您仍然会发现大多数使用 Visual C++ 编程的商店都坚持使用匈牙利符号,或者至少是它的淡化版本。在我们的商店中,我们应用程序的一半是旧版 C++,顶部有一个闪亮的新 C# 层(中间有一个托管的 C++ 层)。我们的 C++ 代码继续使用匈牙利语表示法,但我们的 C# 代码使用您介绍的表示法。我认为它很丑陋,但它是一致的。

我说,在你的项目中使用你的团队想要的任何东西。但是,如果您正在处理遗留代码或加入团队,请坚持使用现有的风格以保持一致性。

19赞 Adam Rosenfield #4

最重要的是要保持一致。如果使用的是旧代码库,请按照旧代码的命名约定一致地命名变量和函数。如果您编写的新代码仅与旧代码交互,请在新代码中使用命名约定,但也要与自己保持一致。

3赞 Marcin #5

我同意这里的其他答案。为了保持一致性,要么继续使用流传下来的风格,要么想出一个适合你的团队的新约定。团队达成一致很重要,因为几乎可以保证您将更改相同的文件。话虽如此,我过去发现一些事情非常直观:

类/结构成员变量应该突出 - 我通常以m_为前缀
全局变量应该突出 - 通常以g_
为前缀 变量通常应以小写开头 函数名称通常应以大写

开头 宏和可能的枚举应全部大写
所有名称都应描述函数/变量的作用,而不应描述其类型或值。

6赞 xyz 10/25/2008 #6

在这个例子中,除了有点丑陋之外,还有什么不喜欢或嘲笑“ppMyObjects”的呢?无论哪种方式,我都没有强烈的意见,但它确实一目了然地传达了有用的信息,而“MyObjects”则没有。

2赞 Nick #7

我自己就是一个匈牙利符号的人,因为我发现它为代码提供了可读性,而且我更喜欢自记录代码而不是注释和查找。

也就是说,我认为你可以为了团队的团结而牺牲你喜欢的风格和一些额外的可维护性。我不相信为了统一代码可读性而保持一致性的论点,特别是如果你为了一致性而降低可读性......这根本没有意义。但是,与你一起工作的人相处在一起,可能值得在查看变量的类型上多混淆一下。

1赞 DavidG #8

这完全取决于个人喜好。我曾在 2 家公司工作过,这两家公司都有类似的计划,其中成员 var 被命名为 m_varName。我从未见过在工作中使用匈牙利符号,而且真的不喜欢它,但又归结为偏好。我的总体感觉是IDE应该负责告诉你它是什么类型,所以只要名称足以描述它的作用(m_color,m_shouldBeRenamed),那就没关系了。我喜欢的另一件事是成员变量、局部 var 和常量命名之间的差异,因此很容易看到函数中发生了什么以及 var 来自哪里。 成员: m_varName 常量:c_varName 本地:varName

16赞 peterchen 10/25/2008 #9

不。 “错误的匈牙利语符号”——尤其是双间接的 pp——对于早期的 C 编译器来说是有一定道理的,因为你可以编写

int * i = 17;
int j = ***i;

甚至没有来自编译器的警告(这甚至可能是正确硬件上的有效代码......

“真正的匈牙利符号”(由 head Geek 链接)仍然是 IMO 的有效选择,但不一定是首选。现代 C++ 应用程序通常有数十或数百种类型,您找不到合适的前缀。

在少数情况下,我仍然在本地使用它,例如,在问题域中具有非常相似甚至相同名称的整数和浮点变量,例如

float fXmin, fXmax, fXpeak; // x values of range and where y=max
int   iXmin, iXMax, iXpeak; // respective indices in x axis vector

但是,在维护始终遵循某些约定(即使松散)的遗留代码时,您应该坚持使用那里的约定 - 至少在要维护的现有模块/编译单元中。

我的理由是:编码标准的目的是遵守最小意外原则。始终如一地使用一种样式比使用哪种样式更重要。

0赞 Roger Nelson #10

如果使用 CamelCase,则约定是将第一个字母大写 对于类、结构和非基元类型名称,以及小写的第一个字母,表示数据成员。 方法的大写往往是一个混合包,我的方法往往是动词,并且已经被括号所困扰,所以我不大写方法。

就我个人而言,我不喜欢阅读 CamelCase 代码,更喜欢下划线小写 数据和方法标识符,将类型大写,并为首字母缩略词保留大写字母 以及我使用宏的罕见情况(警告这是一个宏)。

1赞 bkausbk #11

我也更喜欢CamelCase,事实上,我见过大多数人在C++中使用CamelCase。就个人而言,我不对私有/受保护的成员和接口使用任何前缀:

class MyClass : public IMyInterface {
public:
    unsigned int PublicMember;
    MyClass() : PublicMember(1), _PrivateMember(0), _ProtectedMember(2) {}
    unsigned int PrivateMember() {
        return _PrivateMember * 1234; // some senseless calculation here
    }
protected:
    unsigned int _ProtectedMember;
private:
    unsigned int _PrivateMember;
};
// ...
MyClass My;
My.PublicMember = 12345678;

为什么我决定省略公共成员的前缀:因为公共成员可以像在结构中一样直接访问,并且不会与私有名称冲突。除了使用下划线,我还看到人们使用第一个小写字母来表示成员。

struct IMyInterface {
    virtual void MyVirtualMethod() = 0;
};

根据定义,接口仅包含需要稍后实现的纯虚拟方法。然而,在大多数情况下,我更喜欢抽象类,但这是另一回事了。

struct IMyInterfaceAsAbstract abstract {
    virtual void MyVirtualMethod() = 0;
    virtual void MyImplementedMethod() {}
    unsigned int EvenAnPublicMember;
};

请参阅高完整性 C++ 编码标准手册以获取更多灵感。

评论

0赞 Tom Stickel 4/9/2013
我相信你的意思是说你更喜欢“Pascal”案例(我更喜欢它,大多数 C# 开发人员都知道它是大多数人的标准,网上有大量参考资料来支持这一点)。骆驼大小写“myVirtualMethod”参考:“CamelCase(骆驼大小写)是一个术语,指的是编写复合词的做法,其中标识符的第一个字母是小写的,每个后续连接词的第一个字母是大写的。
6赞 Sebastian Mach 6/19/2013
该名称保留给编译器。_PrivateMember
0赞 bkausbk 7/3/2013
@phresnel:我不认为这是真的。是的,有带有 _ 前缀的内部 C/C++ 方法,也有带有 __ 前缀的方法。但是你自己的类是一种单独的命名空间,你可以自由使用任何你想要的前缀。
5赞 Sebastian Mach 7/3/2013
17.4.3.1.2 全局名称:某些名称和函数签名集始终保留给实现: * 每个包含双下划线 (_ ) 或以下划线开头后跟大写字母 (2.11) 的名称都保留给实现以供任何使用。您正确了 50%:每个以下划线开头的名称都保留给实现,以用作全局命名空间中的名称。
1赞 3 revs, 2 users 95%Tho #12

我的团队遵循以下 Google C++ 代码约定

这是变量名称的示例:

string table_name;  // OK - uses underscore.
string tablename;   // OK - all lowercase.

string tableName;   // Bad - mixed case.

评论

13赞 toddwz 6/6/2017
为什么 tableName 不好?对我来说,它比 tablename 更具可读性。
2赞 NathanAldenSr 9/10/2019
@toddwz 因为霸主决定了。:P
5赞 Sidhin S Thomas 9/17/2020
我会说是坏的,而不是tablenametableName
1赞 Thamme Gowda 9/26/2023
tableName不好C++因为 std lib(至少是现代添加)使用蛇形大小写(见 en.cppreference.com/w/cpp/memory/shared_ptr) 混合并且恕我直言很糟糕。我用 Java 编写代码,它总是使用骆驼大小写,而 python 到处都使用蛇形大小写——两者看起来都很整洁。蛇壳和骆驼壳的混合让我眯着眼睛。snake_casecamelCase