API设计 [英] API design
问题描述
我正在写一个库(通过
串口与多个设备通信)并对设计有一些疑问。我现在有一个
标题和源文件,如下所示:
/ * device.h * /
typedef struct device device ;
int device_open(device ** dev,const char * name);
int device_close(device * dev);
int device_read(device * dev,void * data,unsigned int size);
int device_write(device * dev,const void * data,unsigned int size);
/ * device.c * /
struct device {
/ *这里的一些数据* /
} ;
int
device_open(device ** dev,const char * name)
{
if(dev == NULL)
返回-1;
struct device * out = malloc(sizeof(struct device));
if(out == NULL)
返回-1;
/ *在这里做一些事情* /
>
* dev = out;
返回0;
}
如你所见,我做了内部数据结构通过
typedef和pointe不透明rs到不完整的数据结构。现在我的
问题是:
1.将typedef更改为
typedef struct是否有任何优势设备*设备;
因此隐藏了设备的事实。类型实际上是一个指针。
2.我想添加对第二种类型设备的支持,这恰好与第一种类型非常相似。例如,读/写函数
是不同的,但是开/关函数和
结构本身的内容是相同的。如何在不将
代码复制到一对新的头文件和源文件的情况下实现这一点?
我想将共享代码移动到一个共同的标题和来源
文件并使特定于设备的函数调用常用函数。
但我应该如何处理下面的typdef,因为两个结构都会
在我的情况下,
是相同的。但是我想向图书馆的用户隐藏
。
/ * common.h(仅供内部使用)* /
struct device {
/ *这里的一些数据* /
};
int device_open(device ** dev,const char * name);
/ * device1.h(public)* /
typedef struct device1 device1;
int device1_open(device1 ** dev,const char * name);
....
/ * device2.h( public)* /
typedef struct device2 device2;
int device1_open(device1 ** dev,const char * name);
... 。
I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:
/* device.h */
typedef struct device device;
int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);
/* device.c */
struct device {
/* some data here */
};
int
device_open (device **dev, const char *name)
{
if (dev == NULL)
return -1;
struct device *out = malloc (sizeof (struct device));
if (out == NULL)
return -1;
/* Do some stuff here */
*dev = out;
return 0;
}
As you can see, I made the internal data structure opaque by means of
the typedef and pointers to an incomplete data structure. Now my
questions are:
1. Is there any advantage to change the typedef to
typedef struct device *device;
and thus hiding the fact that the "device" type is actually a pointer.
2. I want to add support for a second type of device, which happens to
be very similar to the first one. For instance the read/write functions
are different, but the open/close functions and the contents of the
struct itself are the same. How can I implement this without copying the
code to a new pair of header and source files?
I was thinking to move the shared code to a common header and source
file and make the device-specific functions call the common functions.
But what should I do with the typdefs below, because both structs would
be the same in my case. But I would like to hide that from the user of
the library.
/* common.h (for internal use only) */
struct device {
/* some data here */
};
int device_open (device **dev, const char *name);
/* device1.h (public) */
typedef struct device1 device1;
int device1_open (device1 **dev, const char *name);
....
/* device2.h (public) */
typedef struct device2 device2;
int device1_open (device1 **dev, const char *name);
....
推荐答案
" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message
"Jef Driesen" <je********@hotmail.com.invalidwrote in message
我正在写一个库(与多个设备通信)在一个
串口上)并对设计有一些疑问。我现在有一个
标题和源文件,如下所示:
/ * device.h * /
typedef struct device device ;
int device_open(device ** dev,const char * name);
int device_close(device * dev);
int device_read(device * dev,void * data,unsigned int size);
int device_write(device * dev,const void * data,unsigned int size);
I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:
/* device.h */
typedef struct device device;
int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);
从标准库中取出一本书。
FILE * fp = fopen(" filename.txt"," w");
如果(!fp)
/ *它失败了* /
fprintf(fp," This file works\\\
");
fclose(fp);
类似
typedef struct device DEVICE;
DEVICE * dev = device_open(" Fred");
if(!dev)
/ *你的设备没有打开* /
device_write(dev,我的名字是弗雷德,15);
device_close(dev);
-
免费游戏和编程好东西。
http:// www。 personal.leeds.ac.uk/~bgy1mm
Take a book out of the standard library.
FILE *fp = fopen("filename.txt", "w");
if(!fp)
/* it failed */
fprintf(fp, "This file works\n");
fclose(fp);
Similarly
typedef struct device DEVICE;
DEVICE *dev = device_open("Fred");
if(!dev)
/* your device didn''t open */
device_write(dev, "my name is Fred", 15);
device_close(dev);
--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm
" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message
news:wo ******************** *** @ phobos.telenet-ops.be ...
"Jef Driesen" <je********@hotmail.com.invalidwrote in message
news:wo***********************@phobos.telenet-ops.be...
我正在写一个库(通过
串口)并对设计有一些疑问。我现在有一个标题
和这样的源文件:
/ * device.h * /
typedef struct device device ;
int device_open(device ** dev,const char * name);
int device_close(device * dev);
int device_read(device * dev,void * data,unsigned int size);
int device_write(device * dev,const void * data,unsigned int size);
I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a header
and source file like this:
/* device.h */
typedef struct device device;
int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);
device_open很难看,IMO:
device * device_open(const char * name);
会有点不那么难看。
device_open is ugly, IMO:
device *device_open (const char *name);
would be a little less ugly.
/ * device.c * /
struct device {
/ * some这里的数据* /
};
int
device_open(device ** dev,const char * name)
{
if(dev == NULL)
返回-1;
struct device * out = malloc(sizeof(struct device));
if(out == NULL)
返回-1;
/ *在这里做一些事情* /
* dev = out;
返回0;
}
如您所见,我通过
typedef和指向不完整数据结构的指针使内部数据结构不透明。现在我的问题
是:
1.将typedef更改为
typedef struct是否有任何优势设备*设备;
因此隐藏了设备的事实。 type实际上是一个指针。
/* device.c */
struct device {
/* some data here */
};
int
device_open (device **dev, const char *name)
{
if (dev == NULL)
return -1;
struct device *out = malloc (sizeof (struct device));
if (out == NULL)
return -1;
/* Do some stuff here */
*dev = out;
return 0;
}
As you can see, I made the internal data structure opaque by means of the
typedef and pointers to an incomplete data structure. Now my questions
are:
1. Is there any advantage to change the typedef to
typedef struct device *device;
and thus hiding the fact that the "device" type is actually a pointer.
这可能是可以接受的(我实际上在一个
点处使用void指针类似):
typedef void * dyt;
其中dyt隐藏它是一个指针。
这是个人偏好。
在我的情况下,''dyt''是一个动态类型的特定''动态类型''API
我...
this may be acceptable (I actually do similar with a void pointer at one
point):
typedef void *dyt;
where dyt hides that it is a pointer.
this is a personal preference though.
in my case, ''dyt'' is a dynamic type for a specific ''dynamic type'' API of
mine...
2.我想添加对第二种类型设备的支持,恰好与第一种设备非常类似。例如,读/写函数是不同的,但是开/关函数和结构的内容
本身是相同的。如何在不将代码复制到
a新的头文件和源文件的情况下实现这一点?
2. I want to add support for a second type of device, which happens to be
very similar to the first one. For instance the read/write functions are
different, but the open/close functions and the contents of the struct
itself are the same. How can I implement this without copying the code to
a new pair of header and source files?
a典型方法是利用结构填充函数指针。
这些存在于每个类型,并由特定的打开实例引用。
struct device_info_s {
int(* close)(device * dev);
int(* read)(device * dev,void * data,unsigned int size);
int(*写)(device * dev,const void * data,unsigned int size);
};
前端函数然后通过这个结构调度。 />
int device_close(device * dev)
{
if(dev-> info-> close)
return(dev-> info-> close(dev));
return(-1);
}
>
这允许将许多不同的子系统插入同一个界面,
并且特别有用,例如,在自定义VFS子系统中,
.. ..
例如,
,我在VFS API上做了一次我称之为''VFILE'',并且,除了我在一点上重写它(内部,
前端API保持或多或少不变),这个API至少在十年左右一直在使用
(这几乎是
我的项目,以及我的第一个''正式''API之一。)
我记得很久以前我最初写的是RDBMS类型
项目(这是我在中学时回来的,或者我认为......)。 (该死的,
中学很久以前......)。
a typical approach is to make use of structs filled with function pointers.
these exist per-type, and are referenced by the specific open instances.
struct device_info_s {
int (*close)(device *dev);
int (*read)(device *dev, void *data, unsigned int size);
int (*write)(device *dev, const void *data, unsigned int size);
};
the frontend functions then dispatch through this struct.
int device_close (device *dev)
{
if(dev->info->close)
return(dev->info->close(dev));
return(-1);
}
this allows plugging lots of different subsystems into the same interface,
and is especially useful, for example, in things like custom VFS subsystems,
....
for example, I did this at one point for a VFS API I called ''VFILE'', and,
apart from the fact that I rewrote it at one point (the internals, the
frontend API remained more or less unchanged), this API has remained in use
for at least around a decade (this is pretty much some of the oldest code in
my projects, and one of my first ''formalized'' APIs).
from what I remember, I originally wrote it long ago for an RDBMS type
project (this was back when I was in middle school or so I think...). (damn,
middle school was a long time ago...).
我想移动共享代码到公共头和源文件
并使特定于设备的函数调用常用函数。但是我应该用下面的typdef做什么,因为在我的情况下两个结构都是相同的
。但是我想向图书馆的用户隐藏它。
/ * common.h(仅供内部使用)* /
struct device {
/ *这里的一些数据* /
};
int device_open(device ** dev,const char * name);
/ * device1.h(public)* /
typedef struct device1 device1;
int device1_open (device1 ** dev,const char * name);
...
/ * device2.h(public)* /
typedef struct device2 device2;
int device1_open(device1 ** dev,const char * name);
...
I was thinking to move the shared code to a common header and source file
and make the device-specific functions call the common functions. But what
should I do with the typdefs below, because both structs would be the same
in my case. But I would like to hide that from the user of the library.
/* common.h (for internal use only) */
struct device {
/* some data here */
};
int device_open (device **dev, const char *name);
/* device1.h (public) */
typedef struct device1 device1;
int device1_open (device1 **dev, const char *name);
...
/* device2.h (public) */
typedef struct device2 device2;
int device1_open (device1 **dev, const char *name);
...
不必要的API碎片是很难看的,特别是如果你将来可能会期待更多
...
unnecessary API fragmentation is ugly, especially if you might expect more
of it in the future...
>
Malcolm McLean写道:
Malcolm McLean wrote:
" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message
"Jef Driesen" <je********@hotmail.com.invalidwrote in message
>我正在写一个库(与一个号码进行通信)设备上的设备,并对设计有一些疑问。我现在有一个
标题和源文件,如下所示:
/ * device.h * /
typedef struct device device;
int device_open( device ** dev,const char * name);
int device_close(device * dev);
int device_read(device * dev,void * data,unsigned int size);
int device_write( device * dev,const void * data,unsigned int size);
>I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:
/* device.h */
typedef struct device device;
int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);
从标准库中取出一本书。
FILE * fp = fopen(" filename.txt"," w");
if(!fp)
/ * it failed * /
fprintf(fp," This file works\\\
");
fclose(fp);
同样
typedef struct device DEVICE;
DEVICE * dev = device_open(" Fred");
if(!dev)
/ *你的设备没有打开* /
device_write(dev,我的名字是弗雷德,15);
device_close(DEV);
Take a book out of the standard library.
FILE *fp = fopen("filename.txt", "w");
if(!fp)
/* it failed */
fprintf(fp, "This file works\n");
fclose(fp);
Similarly
typedef struct device DEVICE;
DEVICE *dev = device_open("Fred");
if(!dev)
/* your device didn''t open */
device_write(dev, "my name is Fred", 15);
device_close(dev);
我的问题不是关于使用
返回值或输出参数返回指针的讨论。我确实选择了最后一个选项
,以便能够直接返回错误代码。这也使错误处理open函数与其他函数类似。
My question was not about the discussion to return the pointer with the
return value or with an output parameter. I did choose the last option
to be able to return an error code directly. This also makes the error
handling of the open function similar to the other functions.
这篇关于API设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!