C 中的不透明指针是什么?

发布于 2024-12-06 15:46:32 字数 31 浏览 0 评论 0原文

我可以知道C中不透明指针概念背后的用法和逻辑吗?

May I know the usage and logic behind the opaque pointer concept in C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

太阳公公是暖光 2024-12-13 15:46:32

不透明指针是一种不透露底层数据细节的指针(根据字典定义:不透明:形容词;无法看透;不透明)。

例如,您可以在头文件中声明(这是来自我的一些实际代码):

typedef struct pmpi_s *pmpi;

它声明了一个类型 pmpi ,它是一个指向不透明结构的指针 struct pmpi_s,因此您声明为 pmpi 的任何内容都将是一个不透明指针。

该声明的用户可以自由编写如下代码:

pmpi xyzzy = NULL;

无需知道结构的实际“定义”。

然后,在了解定义的代码中(即提供 pmpi 处理功能的代码),您可以“定义”该结构:

struct pmpi_s {
    uint16_t *data;     // a pointer to the actual data array of uint16_t.
    size_t sz;          // the allocated size of data.
    size_t used;        // number of segments of data in use.
    int sign;           // the sign of the number (-1, 0, 1).
};

并轻松访问它的各个字段,这是用户可以使用的头文件无法做到这一点。

更多信息可以在维基百科页面上找到不透明指针。

它的主要用途是对您的用户隐藏实施细节封装(不管 C++ 人群会告诉你什么)已经存在很长时间了:-)

你只想发布足够的关于你的库的详细信息,以便用户有效地使用它,仅此而已。< /em> 发布更多信息可以为用户提供他们可能依赖的详细信息(例如,大小变量 sz 位于结构中的特定位置,这可能会导致他们绕过您的控件并进行操作) 然后你就会直接

找到你的客户 。当您更改内部结构时,您会强烈抱怨如果没有该结构信息,您的 API 仅限于您提供的内容,并且您对内部结构的操作自由得以维持。

An opaque pointer is one in which no details are revealed of the underlying data (from a dictionary definition: opaque: adjective; not able to be seen through; not transparent).

For example, you may declare in a header file (this is from some of my actual code):

typedef struct pmpi_s *pmpi;

which declares a type pmpi which is a pointer to the opaque structure struct pmpi_s, hence anything you declare as pmpi will be an opaque pointer.

Users of that declaration can freely write code like:

pmpi xyzzy = NULL;

without knowing the actual "definition" of the structure.

Then, in the code that knows about the definition (ie, the code providing the functionality for pmpi handling, you can "define" the structure:

struct pmpi_s {
    uint16_t *data;     // a pointer to the actual data array of uint16_t.
    size_t sz;          // the allocated size of data.
    size_t used;        // number of segments of data in use.
    int sign;           // the sign of the number (-1, 0, 1).
};

and easily access the individual fields of it, something that users of the header file cannot do.

More information can be found on the Wikipedia page for opaque pointers..

The main use of it is to hide implementation details from users of your library. Encapsulation (despite what the C++ crowd will tell you) has been around for a long time :-)

You want to publish just enough details on your library for users to effectively make use of it, and no more. Publishing more gives users details that they may come to rely upon (such as the fact the size variable sz is at a specific location in the structure, which may lead them to bypass your controls and manipulate it directly.

Then you'll find your customers complaining bitterly when you change the internals. Without that structure information, your API is limited only to what you provide and your freedom of action regarding the internals is maintained.

岁月无声 2024-12-13 15:46:32

不透明指针用于编程接口 (API) 的定义中。

通常,它们是指向不完整结构类型的指针,声明如下:

typedef struct widget *widget_handle_t;

它们的目的是为客户端程序提供一种方法来保存对 API 管理的对象的引用,而不透露有关该对象的实现的任何信息(除了其在内存中的地址) (指针本身)。

客户端可以传递对象,将其存储在自己的数据结构中,并比较两个这样的指针是否相同或不同,但它不能取消引用指针来查看对象中的内容。

这样做的原因是为了防止客户端程序变得依赖于这些细节,以便可以升级实现而无需重新编译客户端程序。

因为不透明指针是类型化的,所以有很好的类型安全措施。如果我们有:

typedef struct widget *widget_handle_t;
typedef struct gadget *gadget_handle_t;

int api_function(widget_handle_t, gadget_handle_t);

如果客户端程序混淆了参数的顺序,编译器将会发出诊断,因为 struct gadget * 正在转换为 struct widget * 没有强制转换。

这就是为什么我们定义没有成员的 struct 类型的原因;每个具有不同新标签的 struct 声明都会引入与先前声明的 struct 类型不兼容的新类型。

客户变得依赖意味着什么?假设 widget_t 具有宽度和高度属性。如果它不是不透明的并且看起来像这样:

typedef struct widget {
  short width;
  short height;
} widget_t;

那么客户端可以这样做来获取宽度和高度:

int widget_area = whandle->width * whandle->height;

而在不透明范例下,它将必须使用访问函数(不是内联的):

// in the header file
int widget_getwidth(widget_handle_t *);
int widget_getheight(widget_handle_t *);

// client code
int widget_area = widget_getwidth(whandle) * widget_getheight(whandle);

注意 widget 作者使用了short 类型来节省结构空间,并且已经向客户端公开了非不透明的界面。假设小部件现在的大小不适合 short,并且结构必须更改:

typedef struct widget {
  int width;
  int height;
} widget_t;

客户端代码现在必须重新编译以获取此新定义。根据工具和部署工作流程,甚至可能存在未完成此操作的风险:旧客户端代码尝试使用新库,并通过使用旧布局访问新结构来行为不当。动态库很容易发生这种情况。库已更新,但依赖程序未更新。

使用不透明接口的客户端无需修改即可继续工作,因此不需要重新编译。它只是调用访问器函数的新定义。它们位于小部件库中,并从结构中正确检索新的 int 类型值。

请注意,历史上(现在仍然在这里和那里)也存在使用 void * 类型作为不透明句柄类型的平淡做法:

typedef void *widget_handle_t;
typedef void *gadget_handle_t;

int api_function(widget_handle_t, gadget_handle_t);

在此方案下,您可以执行此操作,无需任何诊断:

api_function("hello", stdout);

Microsoft Windows API 是一个可以同时使用这两种方式的系统示例。默认情况下,诸如HWND(窗口句柄)和HDC(设备上下文)等各种句柄类型都是void *。所以不存在类型安全; HWND 可能会错误地传递到需要 HDC 的位置。如果这样做:

#define STRICT
#include <windows.h>

那么这些句柄将映射到相互不兼容的类型以捕获这些错误。

Opaque pointers are used in the definitions of programming interfaces (API's).

Typically they are pointers to incomplete structure types, declared like:

typedef struct widget *widget_handle_t;

Their purpose is to provide the client program a way to hold a reference to an object managed by the API, without revealing anything about the implementation of that object, other than its address in memory (the pointer itself).

The client can pass the object around, store it in its own data structures, and compare two such pointers whether they are the same or different, but it cannot dereference the pointers to peek at what is in the object.

The reason this is done is to prevent the client program from becoming dependent on those details, so that the implementation can be upgraded without having to recompile client programs.

Because the opaque pointers are typed, there is a good measure of type safety. If we have:

typedef struct widget *widget_handle_t;
typedef struct gadget *gadget_handle_t;

int api_function(widget_handle_t, gadget_handle_t);

if the client program mixes up the order of the arguments, there will be a diagnostic from the compiler, because a struct gadget * is being converted to a struct widget * without a cast.

That is the reason why we are defining struct types that have no members; each struct declaration with a different new tag introduces a new type that is not compatible with previously declared struct types.

What does it mean for a client to become dependent? Suppose that a widget_t has width and height properties. If it isn't opaque and looks like this:

typedef struct widget {
  short width;
  short height;
} widget_t;

then the client can just do this to get the width and height:

int widget_area = whandle->width * whandle->height;

whereas under the opaque paradigm, it would have to use access functions (which are not inlined):

// in the header file
int widget_getwidth(widget_handle_t *);
int widget_getheight(widget_handle_t *);

// client code
int widget_area = widget_getwidth(whandle) * widget_getheight(whandle);

Notice how the widget authors used the short type to save space in the structure, and that has been exposed to the client of the non-opaque interface. Suppose that widgets can now have sizes that don't fit into short and the structure has to change:

typedef struct widget {
  int width;
  int height;
} widget_t;

Client code must be re-compiled now to pick up this new definition. Depending on the tooling and deployment workflow, there may even be a risk that this isn't done: old client code tries to use the new library and misbehaves by accessing the new structure using the old layout. That can easily happen with dynamic libraries. The library is updated, but the dependent programs are not.

The client which uses the opaque interface continues to work unmodified and so doesn't require recompiling. It just calls the new definition of the accessor functions. Those are in the widget library and correctly retrieve the new int typed values from the structure.

Note that, historically (and still currently here and there) there has also been a lackluster practice of using the void * type as an opaque handle type:

typedef void *widget_handle_t;
typedef void *gadget_handle_t;

int api_function(widget_handle_t, gadget_handle_t);

Under this scheme, you can do this, without any diagnostic:

api_function("hello", stdout);

The Microsoft Windows API is an example of a system in which you can have it both ways. By default, various handle types like HWND (window handle) and HDC (device context) are all void *. So there is no type safety; a HWND could be passed where a HDC is expected, by mistake. If you do this:

#define STRICT
#include <windows.h>

then these handles are mapped to mutually incompatible types to catch those errors.

你是我的挚爱i 2024-12-13 15:46:32

不透明,顾名思义,就是我们看不透的东西。例如,木材是不透明的。不透明指针是指向其内容在定义时不公开的数据结构的指针。

示例:

struct STest* pSTest;

将 NULL 分配给不透明指针是安全的。

pSTest = NULL; 

Opaque as the name suggests is something we can’t see through. E.g. wood is opaque. Opaque pointer is a pointer which points to a data structure whose contents are not exposed at the time of its definition.

Example:

struct STest* pSTest;

It is safe to assign NULL to an opaque pointer.

pSTest = NULL; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文