C使用typedef结构时的设计样式
如果在源文件中使用typedef结构,并且外部系统需要通过接口连接到此类,那么处理输入的正确方法是什么 例如,如果子系统中的源文件C使用typedef结构时的设计样式,c,design-patterns,C,Design Patterns,如果在源文件中使用typedef结构,并且外部系统需要通过接口连接到此类,那么处理输入的正确方法是什么 例如,如果子系统中的源文件 typedef struct { double latitude; double longitude; } GPSLocation; 外部类希望使用以下函数 void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination) 假设我使用
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
外部类希望使用以下函数
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination)
假设我使用接口抽象了它,并有一个外部类调用的函数。该函数应该采用GPSLocation类型的参数(从而强制外部系统#包括存在结构的源文件,而不是现在的外部结构),还是最好保持子系统中使用的所有typedef结构,从而具有如下接口函数
void setupGPSSystem(char* navigationSystem, double startLat, double startLong, double destinationLat, double destinationLong)
GPSLocation
类型属于API,并且应该位于头文件(以.h
结尾的文件)中,API的用户将包括类型属于API,并且应该位于头文件(以.h
结尾的文件)中,API的用户将#包括您可以在接口的公共头中声明类型,并将结构定义隐藏在实现源文件中。因此,您可能有:
gps_系统.h:
typedef struct GPSLocation GPSLocation;
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination);
gps_系统.c:
struct GPSLocation
{
double latitude;
double longitude;
}
这样,您就可以两全其美:用户可以在接口中使用有意义的类型,而实现是私有的。您可以在接口的公共头中声明类型,并将结构定义隐藏在实现源文件中。因此,您可能有:
gps_系统.h:
typedef struct GPSLocation GPSLocation;
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination);
gps_系统.c:
struct GPSLocation
{
double latitude;
double longitude;
}
这样,您就可以两全其美:您的用户可以在界面中使用有意义的类型,而您的实现是私有的。您的子系统可能(应该)有一个头文件,定义其他人用来访问您的系统(API)的函数原型。在这个头文件中定义结构并没有什么错,包括typedef。事实上,这是很常见的。这样,如果您的函数原型遵循该原型,您就可以了。因此:
#ifndef MYSUBSYSTEM_H
#define MYSUBSYSTEM_H
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
void setupGPSSystem(char* navigationSystem,
GPSLocation *start, GPSLocation *destination);
#endif
这将是一个很好的头球。在你的函数中间的新行使它适合。代码>#将
包含在链接到您的系统并设置好的代码中。您的子系统可能(应该)有一个头文件,定义其他人用来访问您的系统(API)的函数原型。在这个头文件中定义结构并没有什么错,包括typedef。事实上,这是很常见的。这样,如果您的函数原型遵循该原型,您就可以了。因此:
#ifndef MYSUBSYSTEM_H
#define MYSUBSYSTEM_H
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
void setupGPSSystem(char* navigationSystem,
GPSLocation *start, GPSLocation *destination);
#endif
这将是一个很好的头球。在你的函数中间的新行使它适合。代码>#包括
,在链接到您的代码中,您已设置。您必须让用户
#包括
一个标题,其中包含接口功能的原型,因此,您也可以将结构定义粘贴在该标题中。您必须让用户#为您的接口函数包含一个带有原型的标题,因此您也可以将结构定义粘贴在该标题中。提到“类”可能不是一个热门主意在一个关于C语言结构的问题:-)只是为了避免任何可能的混淆,例如,C++。
您会问“函数是否应该采用GPSLocation类型的参数(从而强制外部系统#包括存在结构的源文件,…”
您编写的函数不接受GPSLocation类型的参数;它接受指向GPSLocation结构(即地址)的指针类型的参数,这是一件非常不同和美妙的事情
而且,非常正确地说,除了定义GPSLocation的头文件(.h)之外,您没有强迫任何人包含任何内容。这是因为在您的函数项(据我所知)中,您期望指向实例化err的指针,这些结构的副本(开始和结束)当它们存在于调用程序中时。您将通过它们的地址/指针获得每个按引用传递的结构的成员
到目前为止,这是用C传递结构的最好方法——通过指向调用程序的那些结构副本的指针
<>忘记你所给的第二个选择。永远! < P> >在C语言结构的问题中提到“类”可能不是一个很好的想法:-为了避免任何可能的混淆,比如说C++。
您会问“函数是否应该采用GPSLocation类型的参数(从而强制外部系统#包括存在结构的源文件,…”
您编写的函数不接受GPSLocation类型的参数;它接受指向GPSLocation结构(即地址)的指针类型的参数,这是一件非常不同和美妙的事情
而且,非常正确地说,除了定义GPSLocation的头文件(.h)之外,您没有强迫任何人包含任何内容。这是因为在您的函数项(据我所知)中,您期望指向实例化err的指针,这些结构的副本(开始和结束)当它们存在于调用程序中时。您将通过它们的地址/指针获得每个按引用传递的结构的成员
到目前为止,这是用C传递结构的最好方法——通过指向调用程序的那些结构副本的指针
忘记你给出的第二个选择。永远!在设计模块时,你需要决定此模块的用户是否需要直接访问结构中的字段,这将决定你最终定义结构的位置。我将描述几个不同的场景:
1.用户(模块的用户)将直接在您的结构中操作GPS数据。您别无选择,只能将结构定义在头文件(.h)中作为API的一部分。优点是该技术简单,并提供
struct GPSLocation_private
{
GPSLocation gps_public;
int field_0;
int field_1;
};
/** Convert from the public version of the gps object object to the private. */
#define gps_get_private(gps_public) ((struct GPSLocation_private *)(((char *)(gps_public)) - offsetof(struct GPSLocation_private, gps_public)))
void gps_new(GPSLocation **gps)
{
struct GPSLocation_private *priv;
priv = malloc(sizeof(struct GPSLocation_private));
if (priv)
{
priv->field_0 = 1234;
priv->field_1 = 4567;
priv->gps_public.latitude = 1111;
priv->gps_public.longitude = 2222;
gps = &priv->gps_public;
}
else
{
*gps = NULL;
}
}
void gps_set(GPSLocation *gps, double latitude, double longitude)
{
struct GPSLocation_private *priv;
priv = gps_get_private(gps);
/* Do stuff with 'priv'. */
}
void gps_delete(GPSLocation *gps)
{
struct GPSLocation_private *priv;
priv = gps_get_private(gps);
free(priv);
}