我正在尝试创建一个易于正确使用且难以正确使用的API。
想象一下,您有一个函数"bool MyObject_SetLocalDateTime(MyObject *pMyObject, params...)"
,允许客户以YYYY MM DD HH MM SS
格式设置日期和时间:
MyObject *pMyObject = MyObject_Create();
...
MyObject_SetLocalDateTime(pMyObject, params...);
...
MyObject_Destroy(&pMyObject);
该功能的优秀界面是什么?我很感激有关如何使接口易于正确使用且难以在ANSI C(而非C ++中)中使用不正确的任何提示。
答案 0 :(得分:2)
我首先要说的是“正确”是什么。认真。
您希望输入最准确吗?你想要功能不失败吗?你想限制可以输入的值吗?您可能想要考虑您正在创建的内容的要求。
如果调用此函数,数据的格式是什么?它可能只是在用户输入的“YYYY MM DD HH MM SS”的字符串中,那么也许最好采用一个字符串并自己解析这些值。当然,这在你的功能中还有很多工作要做。
此外,如果您正在为自己编写函数,则可以对输入值和测试更加宽容,因为您可能知道预期的内容。如果您要为操作系统创建一个函数,这个函数将有成千上万的人使用这些API,那么您需要更清楚地了解允许的内容并在函数内对它们进行测试。
根据您的情况最“正确”,有很多方法可以指定您引用的简单函数。
bool MyObject_SetLocalDateTime(pMyObject,int YYYY,unsigned int MM,unsigned int DD,int HH,int MM,int SS); //返回值表示成功或失败。
但是,如果消费者为MM传递零,该怎么办?如果消费者通过13?你是使用base-0(通常是C使用的)还是常规的1-12来表示月份(jan-dec)的数字,这从人类月份的角度来看更有意义,但是有点奇怪C程序员的想法?
对于像日期和时间这样的东西,C库有这个定义,这将使你更容易。另外,因为C库已经这样做了,对于使用你的功能的其他用户来说似乎更自然。
您还需要通过“难以正确使用”来定义您的意思。我再一次认真。也许你想要创建一个月(和几天)的枚举,并传递它而不是int。这将为API提供额外的类型检查,但是聪明的API使用者可能会遇到另一个值,因此不要认为您可以跳过测试有效输入。
在你的函数中,你需要验证输入值,无论它们传入什么形式,以确保它们有效,检查你不允许2月30日,并且你允许29对于feb,但每四年一次。日期和时间有很多隐藏的复杂性,这使得依赖已经在OS或运行时库中开发的例程变得明智。
答案 1 :(得分:1)
为什么不简单地使用time_t
和/或struct tm
?
像下面这样的东西会很好:
time_t my_local_time ;
MyObject_SetLocalDateTime(pMyObject, my_local_time ) ;
或
struct tm my_local_time ;
MyObject_SetLocalDateTime(pMyObject, my_local_time ) ;
答案 2 :(得分:0)
您可以在名称中提供一个提示:MyObject_SetLocalDateTime_YMDHMS
答案 3 :(得分:0)
在C
中,我会遵循以下规则:
使用struct const* struct_param
这样可变的输入/输出参数,以便无法在该API内更改其指针值。
将struct const * const structParam
用于不可变输入参数,以便无法在该API内更改其指针值和内容。
在C ++中使用引用而不是指针,我的意思是,C ++显式提供了引用传递,因此您可以减少指针值的传递。