在这里不记录模块功能划分等问题,假定函数接口功能已有明确的定义。这样的话就把讨论局限在了函数名,传入,传出参数的设计上了。
传出参数(不一定指返回值)
- 通常情况下,返回值都是int类型的数据,返回0代表函数执行成功,负数代表失败。
#define SUCCESS 0
#define TIMEOUT 1
#define PARAM_VALID 2
int do_something()
{
if()
return TIMEOUT;
if()
return PARAM_VALID;
return SUCCESS;
}
- 返回值尽量不要是指针类型
//返回值该不该,能不能释放?很难从接口看出来
struct fan *get_fan_info(int id)
{
static struct fan fan;
fan.xx = xx;
....
return &fan //此时不用释放返回值,函数不可重入
struct fan *fan = malloc(sizeof(*fan));
fan->xx = xx;
....
return fan //需要释放返回值,函数可重入。
}
void fan_list()
{
int i;
struct fan *f;
for(i=0;i<MAX;i++){
f = get_fan_info(i);
printf(...about fan..);
free(f) ; //到底要不要执行这句。????
}
get_fan_info(i);// 只是单纯的调一下这个函数,可是会不会内存泄漏???
}
此时我们可以把接口设计成这样
//返回值该不该,能不能释放?很难从接口看出来
int get_fan_info(struct fan *fan,int id)
{
fan->xx = xx;
...
return SUCCESS;
}
void fan_list()
{
int i;
struct fan fan; //参数在栈空间上
for(i=0;i<MAX;i++){
get_fan_info(&fan,i);
printf(...about fan..);
}
get_fan_info(&fan,1) ;//只是单纯的调一下这个函数,会不会内存泄漏??
}
上面的实现,其实很好的贯彻了 谁申请,谁释放的标准。
- 有些情况下,返回值为指针效果很好
struct student *student_new(int id,const char *name); //从函数名便可以看出,此返回值为malloc出来的。
//另外一些明确知道返回的指针所引用的变量,生命周期较长的。
struct student *student_find_by_name(const char *name);//从内存查找一个student.
//此类接口有风险,需要程序员明确内存关系,最好有良好的注释。
- 返回值不应该为结构体。这里就不做具体讨论了。
传入参数
在函数内部最好不要破坏传入参数的内存结构,传入参数的排列顺序最好要有逻辑性。
- 不要破坏传入参数的内存结构
int send_request(const char *method,cJSON *param)
{
....
free(param);
}
int do_something()
{
cJSON *param = cJSON_CreateObject();
cJSON_AddNumberToObject(param,"speed",123);
send_request("set_fan_speed",param);
cJSON_Delete(param); //此时会段错误
}
其实上面代码主要问题是破坏了谁申请谁释放的原则。
- 传入参数的顺序要有一定的逻辑性
//注意都是dest在钱,src在后
void* memcpy(void *desc,const void *src,size_t n);
char *strcpy(char *desc,const char *src);
//思考此时为什么返回值设计为指针类型??
//第一个参数为struct student *
int student_set_id(struct student *s,int id);
int student_set_name(struct student *s,const char *name);
- 传入参数的变量名,一定要表意清晰,尽量不用缩写,内部变量可使用缩写。
int student_set_name_by_id(struct student *student,const char *name)
{
struct student *s = student_find_by_name(name); //内部采用缩写,参数不用缩写。
if
...
return SUCCESS;
}
函数名
函数名要表意清晰,遵守命名规范。几个典型示例如下:
struct student *student_new();
void student_destroy(struct student *student);
struct student *student_find_by_id(int id);
struct student *student_find_by_name(const char *name);