问题引入
初入编程世界,我们不知道什么叫做好代码。一切以实现功能和快速上线项目为主,但编程经验增加,发现代码越来越难写,越来越难改。
导致这样的原因是没有遵循一般性的编程规则或则没有良好的编程风格。俗话说:“无规矩不成方圆”,在编程水平上来后,就更应该遵循规则。
傻瓜都能写出计算机可以理解的代码。唯有能写出人类容易理解的代码的,才是优秀的程序员
好代码的检验标准就是人们是否能轻而易举地修改它
解决过程
规则涉及到:变量、函数、结构体、宏、注释、缩进、空格、花括号等
变量
好代码应能清楚地表明它在做什么,而变量命名是代码清晰的关键
变量按照作用域可以分为:局部变量、全局变量、静态局部变量
变量按照类型可以为:普通变量、结构体变量
-
变量采用匈牙利命名法 例如:
english_book
-
全局变量加前缀g_ 例如:
g_mode
-
静态局部变量加前缀s_ 例如:
s_mode
💡 变量命名法有多种,但总体风格只能体现一种,不能代码中同时出现命名方法
函数
📌 好的命名十分重要,但往往并非唾手可得。只有恰如其分地命名,才能彰显出将大函数分解成小函数的价值
-
若函数无特殊用途,一律限制为
static
例如:static int lib_user_id_get()
-
函数命名采用匈牙利命名法 例如:
int lib_user_id_get()
-
函数参数类型为指针时,若禁止通过间接引用修改值,应限制为const 例如:
static int lib_user_pwd_set(const char *pwd)
-
函数参数类型为结构体时,一律传入结构体指针,若禁止通过间接引用修改值,一律限制为const
-
函数主体部分不能过长,会影响阅读。主体部分应控制在一个显示器页面内
-
一个函数只做一件事,正如函数名定义的那样
-
当函数参数过多时,考虑把一部分参数(根据实际情形考虑)组合一个结构体
-
函数的定义或调用最好能用一行就可以表示,分成多行影响阅读体验
2023-08-30 新增
- 函数的返回值(类型 int)一般用来表示函数是否成功完成,若成功,返回值为0,若失败,返回值为非0。(成功的结果只有一个,失败的原因可能有很多😃)
成功,返回值为0。这样做的一个好处是用来做判断,例如:if (func_x(a,b)) { printf("Failure\n"); return 1; } // do the next something...
结构体
-
结构体名称应该是名词或名词短语,不应该是动词 例如:
CUSTOMER
、ACCOUNT
-
结构体声明时,采用匈牙利命名法,加后缀_ST 例如:
EVENT_DATA_ST
宏
-
宏定义使用全大写字母,连接符用_ 例如:
#define FILE_SIZE 1024
-
宏的名字请用大写字母,不过宏函数的名字可以用小写字母
注释
-
当你感觉需要撰写注释时,请先尝试重构,试着让所有注释都变得多余
-
当逻辑比较复杂难以理解,应该加以注释说明
-
良好的代码是注释尽量少,说明代码可读性良好
-
必要的注释绝不要省略
看一下MQTT源码中的注释
typedef struct
{
/** The eyecatcher for this structure. must be MQTW. */
char struct_id[4];
/** The version number of this structure. Must be 0 or 1
0 means there is no binary payload option
*/
int struct_version;
/** The LWT topic to which the LWT message will be published. */
const char* topicName;
/** The LWT payload in string form. */
const char* message;
/**
* The retained flag for the LWT message (see MQTTClient_message.retained).
*/
int retained;
/**
* The quality of service setting for the LWT message (see
* MQTTClient_message.qos and @ref qos).
*/
int qos;
/** The LWT payload in binary form. This is only checked and used if the message option is NULL */
struct
{
int len; /**< binary payload length */
const void* data; /**< binary payload data */
} payload;
} MQTTClient_willOptions;
/**
* This function attempts to connect a previously-created client (see
* MQTTClient_create()) to an MQTT server using the specified options. If you
* want to enable asynchronous message and status notifications, you must call
* MQTTClient_setCallbacks() prior to MQTTClient_connect().
* @param handle A valid client handle from a successful call to
* MQTTClient_create().
* @param options A pointer to a valid MQTTClient_connectOptions
* structure.
* @return ::MQTTCLIENT_SUCCESS if the client successfully connects to the
* server. An error code is returned if the client was unable to connect to
* the server.
* Error codes greater than 0 are returned by the MQTT protocol:<br><br>
* <b>1</b>: Connection refused: Unacceptable protocol version<br>
* <b>2</b>: Connection refused: Identifier rejected<br>
* <b>3</b>: Connection refused: Server unavailable<br>
* <b>4</b>: Connection refused: Bad user name or password<br>
* <b>5</b>: Connection refused: Not authorized<br>
* <b>6-255</b>: Reserved for future use<br>
*/
LIBMQTT_API int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options);
反思总结
-
C语言代码的最大的难点是命名,包括函数名、变量名、结构体名、共用体名、宏名、头文件名、源文件名 等
-
良好的代码风格可以增加可读性,提高可维护性。
2023-08 新增内容:
-
头文件正确包含的重要性
-
以函数为单位来进行程序编写
-
多用空格和空行
-
状态值,用枚举类型替代宏
参考引用
重构:改善既有代码的设计(第二版)
代码整洁之道