2

我正在尝试创建一个易于正确使用且难以错误使用的 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++)中易于正确使用和难以正确使用的任何提示,我将不胜感激。

4

4 回答 4

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 天,并且您允许 2 月的 29 天,但是仅每四年一次。日期和时间有很多隐藏的复杂性,因此明智地依赖已经在操作系统中开发的例程或运行时库。

于 2012-08-30T22:07:22.460 回答
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 ) ;
于 2012-08-30T21:57:09.230 回答
0

您可以在名称中给出提示:MyObject_SetLocalDateTime_YMDHMS

于 2012-08-30T21:59:07.420 回答
0

C,我会遵循以下规则:

  1. 返回正确的错误代码作为返回类型。
  2. 使用struct const* struct_param如此可变的输入/输出参数,以便它们的指针值无法在该 API 内更改。

  3. 用于struct const * const structParam不可变输入参数,以便它们的指针值和内容不能在该 API 内更改。

在 C++ 中使用引用而不是指针,我的意思是,C++ 显式提供了引用传递,因此您可以减少指针的值传递。

于 2012-08-30T22:07:15.947 回答