C语言中最常见的命名约定是什么?


124

C语言中常用的命名约定是什么?我知道至少有两个:

  1. 具有lower_case_functions的GNU / linux / K&R
  2. ?名称 ?具有UpperCaseFoo函数

我只在这里谈论C。我们的大多数项目是使用C的小型嵌入式系统。

这是我计划用于下一个项目的一个:


C命名约定

Struct              TitleCase
Struct Members      lower_case or lowerCase

Enum                ETitleCase
Enum Members        ALL_CAPS or lowerCase

Public functions    pfx_TitleCase (pfx = two or three letter module prefix)
Private functions   TitleCase
Trivial variables   i,x,n,f etc...
Local variables     lower_case or lowerCase
Global variables    g_lowerCase or g_lower_case (searchable by g_ prefix)

7
我不会在全局变量上使用'g_'前缀;我将强制使用有意义的名称(因此,client_locale而不是cl_lc作为全局变量名称)。经典C不使用驼峰式大小写;我已经用C的驼峰式代码编写了代码,它看起来很奇怪(所以我不再那样做了)。也就是说,这没错-一致性比使用哪种约定更重要。避免封装结构指针的typedef;考虑C标准-拼写为“ FILE *”,而不是FILE_PTR。
乔纳森·莱夫勒

2
@Jonathan Leffler,g_代表全局变量有什么问题?在嵌入式系统中,我遇到了麻烦,在此之前很难通过全局var和extern g_somevar跟踪模块间的依赖关系。我个人认为这通常不是一个好主意,但是出于性能原因通常会完成这种事情。例如,由中断设置的全局标志指示数据已准备就绪。
JeffV

2
值得一提的是,该命名约定主要来自PalmOS API约定。而且,它类似于O'Reilly的书中使用的约定:“使用C和GNU开发工具对嵌入式系统进行编程”。就个人而言,我喜欢函数名称中的TitleCase。我正在考虑在内部链接函数中使用lowerCamelCase(在我的问题中称为私有)。
JeffV

3
@Chris Lutz,我全心全意地同意。尽可能将var保持在最窄的范围内。请注意,实际上我们正在讨论三个范围:函数局部,模块局部(无与变量的外部链接)和具有外部链接的全局变量。在嵌入式系统中通常具有“模块全局变量”。因此,必须注意识别具有外部链接的全局变量,以便将它们保持在最低限度并理解模块交互。这是“ g_”前缀有用的地方。
JeffV

46
我喜欢在全局变量前面加上//。
plafer

Answers:


126

这里最重要的是一致性。也就是说,我遵循GTK +编码约定,可以将其总结如下:

  1. 大写的所有宏和常量:MAX_BUFFER_SIZETRACKING_ID_PREFIX
  2. 结构的名称和类型定义的首字母大写:GtkWidgetTrackingOrder
  3. 在结构上运行的函数:经典C风格:gtk_widget_show()tracking_order_process()
  4. 指针:这里没什么好看的: GtkWidget *fooTrackingOrder *bar
  5. 全局变量:只是不要使用全局变量。他们是邪恶的。
  6. 存在但不应该直接调用的函数,或具有晦涩用途的函数,或诸如此类:开头有一个或多个下划线: _refrobnicate_data_tables()_destroy_cache()

13
在第六点中,我更喜欢使用static并跳过模块前缀,因此,如果gtk_widget_show()是具有文件作用域的函数,则只需widget_show()添加静态存储类即可。
8月Karlstrom

26
关于第6点的附加说明:C标准具有一些有关保留名称的规则,这些规则始于_实现和将来使用。以名字开头的名字有一些例外,_但我认为记住这一点是不值得的。一个安全的规则是永远不要使用以_代码开头的名称。相关的C常见问题解答条目:c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013 2014年

5
#2更具体地说是上骆驼案帕斯卡案。骆驼案或小骆驼案在首字母使用小写。
克林特·帕奇

9
局部多字变量呢?my_var或myVar?
迪恩·古维兹

4
Global variables: just don't use global variables. They are evil.-除非您从事嵌入式项目,并且有1024字节的RAM和8MHz CPU。
卡米尔

30

“结构指针”不是需要命名约定子句覆盖它们的实体。他们只是struct WhatEver *。不要掩盖一个事实,即聪明的,“显而易见的” typedef包含了一个指针。它没有用,输入时间更长,并且破坏了声明和访问之间的平衡。


29
对“不要隐藏指针”的内容+1 -即使此答案并未解决其余大部分问题(尚未解决)。
乔纳森·勒夫勒

1
@unwind,我倾向于同意。但是,有时不希望将指针从外部取消引用,并且它实际上是指向使用者的句柄,而不是指向将要使用的结构的实际指针。那就是我留下的TitleCasePtr。typedef struct {字段} MyStruct,* MyStructPtr;
JeffV

我正在删除TitleCasePtr,它分散了实际问题的注意力。
JeffV

1
因为指针类型声明减少了混乱,尤其是在函数签名中,并且声明和访问之间的“不平衡”仅显示在实现文件中,所以我从-1开始-客户端不(不应)直接访问字段成员。
8月Karlstrom

1
@AugustKarlstrom好。我不了解实现文件的“唯一”含义,那不是代码吗?我并没有将问题解释为仅与“外部”名称有关。所有代码都是某种程度上的“实现”。
2013年

17

首先,C没有公共/私有/虚拟功能。那是C ++,它有不同的约定。在C语言中,通常有:

  • ALL_CAPS中的常量
  • 用下划线分隔结构或函数名称中的单词,在C语言中几乎看不到驼峰式大小写;
  • struct,typedef,union,union和struct的成员和枚举值通常使用小写字母(以我的经验),而不是将首字母大写的C ++ / Java / C#/ etc约定,但我想在也是。

C ++更复杂。我在这里看到了真正的混合。类名或小写+下划线的驼峰式大小写(以我的经验更常见)。结构很少使用(通常是因为库需要结构,否则将使用类)。


@cletus,我意识到这一点。私有是指未在模块头文件中公开的功能,以及不打算由模块外部的代码使用的功能。Public是旨在供外部使用的模块API函数。
JeffV

3
您可以将静态函数视为私有函数。这个问题没有提到虚拟。但是+1表示“很少看到C中的驼峰式”。
乔纳森·勒夫勒

2
我认为Jeff的意思external linkage是“公共职能”和internal linkage“私人职能”。
09年

1
我已经看到了以ak和kBufferSize开头的常量。不知道从哪里来。
JeffV

2
ALL_CAPS也经常用于枚举值。
caf

14

您知道,我喜欢保持简单,但要清楚...所以这就是我在C语言中使用的:

  • 琐碎变量i,n,c,etc ...(仅一个字母。如果一个字母不清楚,则将其设为局部变量)
  • 局部变量lowerCamelCase
  • 全局变量g_lowerCamelCase
  • 常量变量ALL_CAPS
  • 指针变量:将a添加p_到前缀。对于全局变量gp_var,对于局部变量p_var,对于const变量p_VAR。如果使用远指针,则使用fp_代替p_
  • 结构:(ModuleCamelCase模块=完整的模块名称,或2-3个字母的缩写,但仍在CamelCase。中)。
  • 结构成员变量lowerCamelCase
  • 枚举ModuleCamelCase
  • 枚举值ALL_CAPS
  • 公共职能ModuleCamelCase
  • 私人职能CamelCase
  • 巨集CamelCase

我用typedef构造,但标签和typedef使用相同的名称。标签并不意味着通常使用。相反,最好使用typedef。我还将在公共模块头中声明typedef进行封装,以便在定义中使用typedef的名称。

完整 struct 示例

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};

我对qt框架一无所知,但是您可以使用所需的任何样式格式编写代码。据我所知,没有什么可以阻止您。
肖恩·拉米(SeanRamey)'18年

10

C#,Java,C,C ++和目标C编码进行,我采用了一种非常简单明了的命名约定来简化我的生活。

首先,它依赖于现代IDE(例如eclipse,Xcode ...)的功能,并且可以通过悬停或ctrl单击来获取快速信息...接受,我禁止使用任何前缀,后缀和其他仅由IDE给出的标记。

然后,约定:

  • 任何名称都必须是易读的句子,以解释您所拥有的。就像“这是我的约定”。
  • 然后,使用4种方法从句子中获取约定:
    1. THIS_IS_MY_CONVENTION用于宏,枚举成员
    2. ThisIsMyConvention用于文件名,对象名(类,结构,枚举,联合...),函数名,方法名,typedef
    3. this_is_my_convention全局和局部变量,
      参数,结构和联合元素
    4. thisismyconvention [可选]非常局部和临时的变量(例如for()循环索引)

就是这样。

它给

class MyClass {
    enum TheEnumeration {
        FIRST_ELEMENT,
        SECOND_ELEMENT,
    }

    int class_variable;

    int MyMethod(int first_param, int second_parameter) {
        int local_variable;
        TheEnumeration local_enum;
        for(int myindex=0, myindex<class_variable, myindex++) {
             localEnum = FIRST_ELEMENT;
        }
    }
}

8

我建议不要混合使用驼峰和下划线分隔(就像您为结构成员建议的那样)。这很混乱。您可能会想,嘿,我有,get_length所以我大概应该有make_subset,然后您发现它实际上是makeSubset。使用最少惊讶的原则,并保持一致。

我发现CamelCase对键入名称很有用,例如结构,typedef和枚举。不过,仅此而已。对于所有其他内容(函数名称,结构成员名称等),我使用underscore_separation。


1
是的,关于任何命名约定的主要内容是可预测性和一致性。另外,由于C库本身使用_来表示所有小写字母,所以我建议使用它,这样您就不必在项目中处理2种不同的命名约定(假设您不必为libc编写包装器即可它符合您的命名..但多数民众赞成总值)
Earlz

它也使用typedef并在结尾加上一个“ t”,但是我看不到有人建议这样做。实际上,标准库甚至不一致:div_t(stdlib.h)是一个结构,而tm(time.h)也是如此。另外,看看tm struct成员,它们都以tm为前缀,这看起来毫无意义且丑陋(IMO)。
JeffV

1
“我发现CamelCase对于键入名称很有用...”如果以大写字母开头,则实际上是PascalCase。
Tagc


3

我被一件事弄糊涂了:您打算为一个新项目创建一个新的命名约定。通常,您应该具有公司或团队范围内的命名约定。如果您已经有具有任何形式的命名约定的项目,则不应更改新项目的约定。如果以上约定只是您现有做法的编纂,那么您就是黄金。它与现有的事实上的标准差异越大,在新标准中获得关注的难度就越大。

关于我要添加的唯一建议是,我喜欢uint32_t和size_t样式的类型末尾的_t。尽管有些人可能抱怨这只是“反向”匈牙利语,但对我来说却是C-ish。


3
好吧,这里的约定到处都是而且不一致,这就是为什么我要开始记录一个约定。另外,这就是为什么我要问。了解社区共识是什么。
JeffV

我知道那种痛苦。但是必须有一些现有约定中最受欢迎的子集。您应该从此处开始,而不要在随机的Internet网页上。另外,您还应该问问其他开发人员,他们认为什么很好。
jmucchiello

7
我相信以_t结尾的类型名称是POSIX标准保留的。
caf

4
保留以_t结尾的名称。见gnu.org/software/libc/manual/html_node/Reserved-Names.html,“名称以‘_t’端保留额外的类型名称。”
艾蒂安

2

您还应该考虑单词顺序,以使自动完成名称更加容易。

好的做法:库名称+模块名称+操作+主题

如果零件不相关,则跳过该零件,但始终应至少显示一个模块名称和一个动作。

例子:

  • 函数名称:os_task_set_priolist_get_sizeavg_get
  • 定义(这里通常没有动作部分):OS_TASK_PRIO_MAX

0

可能有很多,主要是IDE指示一些趋势,并且C ++约定也在推动。通常对于C:

  • UNDERSCORED_UPPER_CASE(宏定义,常量,枚举成员)
  • underscored_lower_case(变量,函数)
  • CamelCase(自定义类型:结构,枚举,联合)
  • uncappedCamelCase(OPPA Java风格)
  • UnderScored_CamelCase(变量,命名空间下的函数)

对于全局变量来说,匈牙利表示法很好,但对于类型而言却不是。即使是琐碎的名字,也请至少使用两个字符。


-1

我认为这些可以对初学者有所帮助:c中变量的命名约定

  1. 您必须使用字母字符(az,AZ),数字(0-9)和下划线(_)。不允许使用任何特殊字符,例如:%,$,#,@等。因此,可以将user_name用作变量,但不能使用user&name
  2. 单词之间不能使用空格。因此,您可以使用user_name或username或username作为变量,但不能使用user name
  3. 无法以数字开始命名。因此,可以将user1或user2用作变量,但不能使用1user
  4. 它是区分大小写的语言。大写和小写都很重要。如果使用诸如username之类的变量,则不能使用USERNAME或Username作为父亲使用。
  5. 您不能将任何关键字(char,int,if,for,while等)用于变量声明。
  6. ANSI标准可识别长度为31个字符的变量名

这篇文章显然旨在讨论命名约定,而不是限制。您列出的是您甚至无法做的事情,因为那是语法错误。
大通
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.