C中的接口 [英] Interfaces in C

查看:71
本文介绍了C中的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设计一个应用程序,遇到一个实现问题.我有以下结构定义:

I'm designing an application and came across an implementation issue. I have the following struct definition:

app.h:

struct application_t{
    void (*run_application)(struct application_t*);
    void (*stop_application)(struct application_t*);
}

struct application_t* create();

当我尝试实现"此application_t时出现问题.我倾向于定义另一个结构:

The problem came when I tried to "implement" this application_t. I tend to define another struct:

app.c:

struct tcp_application_impl_t{
    void (*run_application)(struct application_t*);
    void (*stop_application)(struct application_t*);
    int client_fd;
    int socket_fd;
}

struct application_t* create(){
     struct tcp_application_impl_t * app_ptr = malloc(sizeof(struct tcp_application_impl_t));
     //do init
     return (struct application_t*) app_ptr;
}

因此,如果我按如下方式使用它:

So if I use this as follows:

#include "app.h"

int main(){
    struct application_t *app_ptr = create();
    (app_ptr -> run_application)(app_ptr);    //Is this behavior well-defined?
    (app_ptr -> stop_application)(app_ptr);   //Is this behavior well-defined?
}

令我困惑的问题是,如果我对(app_ptr -> run_application)(app_ptr);的电话打了UB.

The problem confusing me is if I this calling to (app_ptr -> run_application)(app_ptr); yeilds UB.

app_ptr的静态类型",如果为struct application_t*,但动态类型"为struct tcp_application_impl_t*. N1570 6.2.7(p1)与struct application_tstruct tcp_application_t不兼容:

The "static type" of app_ptr if struct application_t*, but the "dynamic type" is struct tcp_application_impl_t*. The struct application_t and struct tcp_application_t are not compatible by N1570 6.2.7(p1):

其成员之间应存在一一对应的关系,例如 每对对应的成员都声明为兼容 类型

there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types

在这种情况下显然不正确.

which obviously is not true in this case.

您能否提供对标准的解释说明?

Can you please provide a reference to the Standard explaining the behavior?

推荐答案

您的两个结构不兼容,因为它们是不同的类型.您已经找到了兼容类型"一章,该章定义了使两个结构兼容的原因.稍后,当您使用指向错误类型的指针(严格按照6.5/7违反别名)访问这些结构时,UB就会出现.

Your two structs aren't compatible since they are different types. You have already found the chapter "compatible types" that defines what makes two structs compatible. The UB comes later when you access these structs with a pointer to the wrong type, strict aliasing violation as per 6.5/7.

解决这个问题的明显方法是:

The obvious way to solve this would have been this:

struct tcp_application_impl_t{
    struct application_t app;
    int client_fd;
    int socket_fd;
}

由于tcp_application_impl_t是成员中包含application_t的聚合,因此这些类型可能会别名.

Now the types may alias, since tcp_application_impl_t is an aggregate containing a application_t among its members.

对此进行明确定义的另一种方法是,使用隐藏在C17 6.5.2.3/6中的联合通用初始序列"的狡猾特殊规则:

An alternative to make this well-defined, is to use a sneaky special rule of "union common initial sequence", found hidden in C17 6.5.2.3/6:

为了简化联合的使用,做出了一项特殊保证:如果联合包含 几个具有共同初始序列的结构(请参见下文),以及联合 对象当前包含这些结构之一,因此可以检查通用对象 声明联合完成类型的任何地方的任何部分的初始部分 是可见的.如果相应的成员,则两个结构共享共同的初始序列 具有一个或多个初始成员序列的兼容类型(对于位域,具有相同的宽度).

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

这将允许您使用声明的原始类型.但是在同一个翻译单元中的某处,您将不得不添加一个伪联合typedef来利用上述规则:

This would allow you to use your original types as you declared them. But somewhere in the same translation unit, you will have to add a dummy union typedef to utilize the above rule:

typedef union
{
  struct application_t app;
  struct tcp_application_impl_t impl;
} initial_sequence_t;

您不需要实际使用此联合的任何实例,只需将其放在可见的位置即可.这告诉编译器,就这两种类型而言,只要它们的公共初始序列都行,就可以对其进行别名.在您的情况下,这意味着函数指针而不是tcp_application_impl_t中的尾随变量.

You don't need to actually use any instance of this union, it just needs to sit there visible. This tells the compiler that these two types are allowed to alias, as far as their common initial sequence goes. In your case, it means the function pointers but not the trailing variables in tcp_application_impl_t.

免责声明.常见的初始序列技巧显然有争议,编译器用它来完成委员会未曾打算的其他事情.可能在C和C ++中的工作方式有所不同.参见联盟"punning"结构w/通用初始序列":为什么C(99+)而不是C ++规定了联合类型的可见声明"?

Disclaimer. The common initial sequence trick is apparently a bit controversial, with compilers doing other things with it than the committee intended. And possibly works differently in C and C++. See union 'punning' structs w/ "common initial sequence": Why does C (99+), but not C++, stipulate a 'visible declaration of the union type'?

这篇关于C中的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆