在C ++

时间:2016-03-28 17:21:42

标签: c++ c casting undefined-behavior void-pointers

我通过编写C接口来包装C ++库。出于这个原因,我创建了一个C头文件,其中大多数函数返回/接受void*而不是C ++类指针。

我知道在C ++中从/转换为void是危险的,请参阅 Casting to void* and Back to Original_Data_Type*

目前,在继承之前,我总是在分配给void *之前将其转换为对象的基类

void* temp = static_cast<BaseClass*>(ptr)

并返回

BaseClass* base = static_cast<BaseClass*>(voidPtr)
DerivedClass* derived = dynamic_cast<DerivedClass*>(base)

但是在头文件中使用void*会删除语义并使复杂的函数难以阅读。 例如:

void myComplexFunc(void* index, void* data, void* somethingElse)

为了减轻这种情况,我想使用typedef,即使他们不提供任何类型的安全性,至少他们会给读者一些见解。 将之前的代码段与此

进行比较
extern "C" 
{
...
typedef void Index;
typedef void DBRecord;
typedef void DBResult;
void myComplexFunc(Index* index, DBRecord* data, DBResult* somethingElse)
...
}

基本上,当多个void*用作函数的参数时,这些typedef充当文档的排序(请记住,我用10个方法包装多个C ++类,所以&#39;许多函数都将void *作为第一个参数。)

因此我想使用typedefs

extern "C" // In.h file (declaration)
{
typedef void Index;
...
Index* getIndex();
void modifyIndex(Index* index);
...
// In .cpp file (definition)
Index* getIndex() {
  DerivedCppIndex* derived = ...
  BaseCppIndex* base = static_cast<BaseCppIndex*>(derived)
  return base;
}
...
void modifyIndex(Index* index) {
  BaseCppIndex* base = static_cast<BaseCppIndex*>(index);
  DerivedCppIndex* derived = dynamic_cast<DerivedCppIndex*>(base);
  ...
}

使用typedef而不是void *会导致任何关于赋值给void *的问题吗?

2 个答案:

答案 0 :(得分:2)

它不应该造成任何麻烦,但它只会给API用户一种错误的安全感(因为任何指针也会起作用)。如果您执行以下操作,则无法阻止编译器抱怨:

int i;
// ....
modifyIndex(&i);

因此,虽然您没有遇到任何问题,但您也无法进行任何编译时检查和强制执行。

请注意,您可以选择简单地声明类而不实际定义它。

解决空洞指针的正确方法&#34;问题&#34; (并且它不是一个问题,它只是C(以及C ++)的一个方面,它可能使代码难以维护而没有适当的关注/文档)是以某种方式将Index公开为不透明类型; e.g。

// index.h
class Index;
// ...
void modifyIndex(Index *i);

答案 1 :(得分:0)

void创建typedef有点尴尬。更常见的做法是将void*定义为IndexHandle并强制代码的客户端读取或传递不透明句柄类型的值作为参数。所有的转换都应该在你的代码中进行。