使用 typedef 结构时的 C 设计风格
当在源文件中使用 typedef 结构并且外部系统需要通过接口连接到此类时,处理输入的正确方法是什么?
一个例子是,如果子系统内的源文件具有
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
并且外部类想要使用以下函数,
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination)
可以说我使用接口对其进行抽象,并具有外部类调用的函数。该函数是否应该采用 GPSLocation 类型的参数(从而强制外部系统 #include
包含该结构的源文件,现在不再那么外部),或者最好保留子结构中使用的所有 typedef 结构-system 并因此具有如下接口函数?
void setupGPSSystem(char* navigationSystem, double startLat, double startLong, double destinationLat, double destinationLong)
When one uses typedef structs within a source file and an external system will need to connect to this class via an interface, what is the correct way to handle the input?
One example is if a source file inside a sub-system has
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
and an external class wants to use the following function
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination)
Lets say I abstract this using the interface and have a function which the external class calls. Should the function take arguments of type GPSLocation(thus forcing the external system to #include
the source file with the struct present, not so external now) or is it better to keep all typedef structs used within the sub-system and thus having an interface function as follows?
void setupGPSSystem(char* navigationSystem, double startLat, double startLong, double destinationLat, double destinationLong)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以在接口的公共标头中声明类型,并将结构定义隐藏在实现源文件中。因此,您可能拥有:
gps_system.h:
gps_system.c:
这样,您就可以两全其美:您的用户可以在接口中使用有意义的类型,并且您的实现是私有的。
You can declare the types in your interface's public header, and have the structure definitions hidden in your implementation source files. So, you might have:
gps_system.h:
gps_system.c:
That way, you get the best of both worlds: your users can use meaningful types in the interface, and your implementation is private.
在设计模块时,您需要决定该模块的用户是否需要直接访问结构中的字段,这将决定您最终在哪里定义结构。我将描述一些不同的场景:
1。 (模块的)用户将直接操作结构中的 GPS 数据。您别无选择,只能在头文件 (.h) 文件中定义结构作为 API 的一部分。优点是这种技术很简单,并且使用户能够根据需要为结构静态或动态分配内存(因为结构的组成对于其他模块来说是已知的)。缺点是该技术不会隐藏您的数据;它可能被用户有意或无意地破坏。
2.用户并不关心“GPS位置”是什么,它总是使用模块的函数来操作您的数据结构。在这种情况下,您的结构可以是不透明的。您在头文件 (.h) 中声明它,并在源文件 (.c) 中定义它(如 Graham 的答案所述)。优点是您可以隐藏所有数据,这意味着用户无法轻易破坏它或(在专有库的情况下)了解它是如何实现的。缺点是您的模块必须管理不透明类型的分配(和释放)(有关此想法的扩展,请参阅下面的第 3 点)。
gps_system.h
gps_system.c
3.您希望授予用户对某些字段的只读访问权限,但隐藏其他字段。这可能是一种有用的技术,可以隐藏实现细节并防止用户损坏您的数据,同时可以轻松访问有用的数据信息。缺点是您仍然需要模块来管理不透明类型的分配。
gps_system.h
gps_system.c
In designing the module you need to decide whether users of this module need access to the fields within the structure directly, and this will determine where you end up defining the structure. I'll describe a few different scenarios:
1. A user (of the module) will directly manipulate the GPS data within your structure. You have no choice but to define the structure in a header (.h) file as part of the API. The advantage is that this technique is simple and gives the user the ability to statically or dynamically allocate memory for your structure as required (since the structure's make-up is known to your other modules). This disadvantage is that this technique does not hide your data; it can be intentionally or inadvertently corrupted by the user.
2. A user does not care what a "GPS location" is, it will always use the module's functions to operate on your data structure. In this case your structure can be opaque. You declare it in the header (.h) file and define it in the source (.c) file (as covered by Graham's answer). The advantage is you get to hide all of your data which means a user can't easily corrupt it or (in the case of a proprietary library) understand how it has been implemented. The disadvantage is your module must manage the allocation (and freeing) of your opaque type (see point 3 below for an expansion of this idea).
gps_system.h
gps_system.c
3. You'd like to give the user read-only access to some fields but to hide others. This can be a useful technique for hiding implementation details and to prevent a user from corrupting your data while making it easy to access useful information. The disadvantage is you still need your module to manage allocation of the opaque type.
gps_system.h
gps_system.c
您的子系统可能(应该)有一个头文件,定义其他人用来访问您的系统的函数原型(API)。在该头文件中定义结构并使用 typedef 完成也没有什么问题。事实上这很常见。这样,只要你的函数原型遵循该原型,就可以了。所以这个:
会是一个很好的标题。在函数中间换行以使其适合 SO。
#include
在链接到您的代码中,您就完成了设置。Your subsystem probably (ought to) have a header file defining the function prototypes other people use to access your system (the API). There is nothing wrong with also defining your struct in that header file, complete with typedef. In fact it is very common. That way, providing your function prototype follows that prototype, you're ok. So this:
Would make a good header. Newline in the middle of your function to make it fit on SO.
#include
that in the code that is linking to yours and you're set.GPSLocation
类型属于 API,并且应该位于头文件(以.h
结尾的文件)中,API 的用户将#include< /代码>。
The
GPSLocation
type belongs to the API, and should be on a header file (a file ending in.h
), that users of your API will#include
.您必须为用户#include 提供一个包含接口函数原型的标头,因此您也可以将结构定义粘贴在该标头中。
You have to make the user
#include
a header with the prototypes for your interface functions, so you may as well stick the struct definition in that header.在有关 C 语言结构的问题中提及“类”可能不是一个热门的想法:-)只是为了避免与 C++ 等可能产生的混淆。
您问“该函数是否应该采用 GPSLocation 类型的参数(从而强制外部系统#include 具有结构的源文件,...”
您编写的函数不采用GPSLocation 类型的参数;它采用 GPSLocation 结构的指针类型的参数(即地址),这是一个非常不同且美妙的事情,
并且非常正确和正确 。 ,您不会强迫任何人 #include 除了定义 GPSLocation 的头文件 (.h) 之外的任何内容,这是因为在您的函数条目中(据我所知)您期望指向
的指针。 因为它们存在于调用程序中,您将通过它们的地址/指针获得每个按引用传递的结构的成员。实例化 错误,这些结构的副本(开始和结束) , 到目前为止 在 C 中传递结构的最佳方法 - 通过指向调用程序的这些结构的副本的指针,
永远忘记您给出的第二个选择!
It might not be such a hot idea to mention "class" in a question about C-language structs :-) Just to avoid any possible confusion with, say, C++.
You ask "Should the function take arguments of type GPSLocation(thus forcing the external system to #include the source file with the struct present, ... "
The function as you've written it does not take arguments of type GPSLocation; it takes arguments of type pointer to (i.e., address of) a GPSLocation struct, a very different and a wonderful thing.
And, very properly and correctly, you're not forcing anybody to #include anything except the header (.h) file that defines GPSLocation. That's because in your function entry (as I understand it) you are expecting pointers to
instantiationserr, copies of those structs (start and end) as they exist in the calling program. You'll get at the members of each passed-by-reference struct through their addresses/pointers.This is by far the best way to pass structs in C -- via pointers to the calling program's copies of those structs.
Forget about the second choice you gave. Forever!