Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对于指向C+的不透明C指针,正确的typedef是什么+;上课? 有几十个这样的问题和博客文章,描述用C API包装C++类。范例_C++_C_Typedef - Fatal编程技术网

对于指向C+的不透明C指针,正确的typedef是什么+;上课? 有几十个这样的问题和博客文章,描述用C API包装C++类。范例

对于指向C+的不透明C指针,正确的typedef是什么+;上课? 有几十个这样的问题和博客文章,描述用C API包装C++类。范例,c++,c,typedef,C++,C,Typedef,大多数答案和博客帖子都是这样写的: typedef void* CMyClass; 但也有人说这很糟糕,因为它没有提供类型安全性。他们提出了不透明结构的各种变体,没有任何解释。我可以复制上面的片段,继续我的生活(我将在这段时间内继续),但我想一劳永逸地知道 哪种形式最好 它在void*上提供了哪些保证 它是如何工作的 void*的问题在于,它无法防止意外分配不兼容的指针 typedef void *CMyClass; int i = 1; CMyClass c = &i; // No

大多数答案和博客帖子都是这样写的:

typedef void* CMyClass;
但也有人说这很糟糕,因为它没有提供类型安全性。他们提出了不透明结构的各种变体,没有任何解释。我可以复制上面的片段,继续我的生活(我将在这段时间内继续),但我想一劳永逸地知道

  • 哪种形式最好
  • 它在
    void*
    上提供了哪些保证
  • 它是如何工作的

void*的问题在于,它无法防止意外分配不兼容的指针

typedef void *CMyClass;
int i = 1;
CMyClass c = &i; // No complaints
如果您将typedef改为某个唯一的不透明类型,编译器将帮助您

typedef struct MyClass *CMyClass;
int i = 1;
CMyClass c = &i; // BOOM!
我认为在C语言中这不是一个错误,但Clang6.0警告我(即使没有启用任何警告)


在C++中使用<代码> struct MyType <代码> > < /P> 使用

typedef struct MyType*pMyType作为您的公共句柄

<>你的“C”API应该在C++和C++中(在C++中使用<代码>外部代码> C > <代码>包装,以获得正确的链接。您将接近max type safety


现在,
struct MyHandle{void*private_ptr;}”是另一种选择:这避免了将C++类型的名称暴露给C.,只要隔离了与“代码> PrimeTyPPTR <代码>的直接交互,就可以实现一小部分功能,它在其他任何地方都是类型安全的。

第一件事是,
void*
确实不是一个好选择,因为它通过静默地接受任何不相关的指针使API更容易出错。因此,更好的办法是向某个结构添加一个转发声明,并接受指向该结构的指针:

#ifdef __cplusplus
extern "C"
{
#endif

struct CMyClassTag;
typedef struct CMyClassTag CMyClass;

void CMyClass_Work(CMyClass * p_self);

#ifdef __cplusplus
}
#endif
下一步是显式地告诉用户该指针是不透明的,不应该通过将指针隐藏为不必要的实现细节来取消引用:

typedef struct CMyClassTag * CMyClassHandle;

void CMyClass_Work(CMyClassHandle h_my_class);
另外,依靠用户正确地使用这个接口,您可以创建真正的句柄类型,而不是不透明的指针。这可以通过几种方式完成,但主要思想是传递一些模糊的整数标识符,并在运行时将其映射到库端的实际指针:

typedef uintptr_t CMyClassHandle;

void CMyClass_Work(CMyClassHandle h_my_class);

// impl
void CMyClass_Work(CMyClassHandle h_my_class)
{
     auto it{s_instances_map.find(h_my_class)};
     if(s_instances_map.end() != it)
     {
         auto & self{it->second};
         // ...
     }
}

问题是,如果您声明
typedef struct CMyClass\u*CMyClass您需要显式强制转换。示例:相关:不要键入def指针!那么,那些批评家们还推荐哪种方式呢?为什么它对你不起作用?C是从C++支持的,但是反过来不是真的。这意味着没有有效的通用机制可用于管理C中的类。例如,假设C程序中使用了全局实例(
static
)。。。谁调用那个对象的构造函数?+ 1,用于提及C++声明。code>struct T
class T
是不同的声明,例如,如果混合使用
struct
class
来引用相同的名称,则Clang将发出错误。@MatthieuM。如何触发此错误(假设
-pedantic errors-Wno error-Wall-Wextra
)?我最多只能得到一个带有clang 6.0的
-Wmismatched标记,但这显然是一个警告,而不是一个错误。@Ruslan:问得好。我只使用
-Werror
进行编译,所以这可能是一个警告。对于可移植性来说也是非常有用的,因为在MSVC的ABI中有不同的链接。我最后用私有指针来构造Strut,因为我的C++ API返回了SyrdY-PTR,这是我唯一能找到的明智方法。对于C程序员来说,将指针隐藏在
typedef
后面被广泛认为是不好的风格。在这种特殊情况下,它可能是合理的,因为指针指向C中未知的东西,所以您可以认为只提供了一个“不透明句柄”。不过,严格来说,“C++结构”可能不同于C中的结构(比如vtables),所以我总是选择第二个选项。
typedef uintptr_t CMyClassHandle;

void CMyClass_Work(CMyClassHandle h_my_class);

// impl
void CMyClass_Work(CMyClassHandle h_my_class)
{
     auto it{s_instances_map.find(h_my_class)};
     if(s_instances_map.end() != it)
     {
         auto & self{it->second};
         // ...
     }
}