【问题标题】:Casting to void* and typedefs in C++在 C++ 中强制转换为 void* 和 typedef
【发布时间】:2016-03-28 17:21:42
【问题描述】:

我正在通过编写 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,即使它们没有提供任何类型安全性,至少它们会给读者一些见解。 比较之前的sn-p和这个

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

基本上,当多个 void* 用作函数的参数时,这些 typedef 充当文档的一种排序(请记住,我正在包装多个 C++ 类,每个类都有 10 个方法,所以有很多函数需要一个 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* 的问题造成任何麻烦?

【问题讨论】:

  • 你这样做有什么理由吗?这似乎是一个非常糟糕的主意。
  • 我认为(在写下我的答案之后)他不想将他的类型层次结构暴露给用户;所以虽然从他的代码DerivedIndex 可以转换为Index,但如果看到的只是class Index; class DerivedIndex,它就行不通了。
  • 听起来像是 x-y 问题,请提供一些用例和背景。
  • 从字面上回答问题,使用索引为typedefed 的Index*void 与使用void* 没有区别。不确定 OP 实际上在问什么。
  • @SergeyA 我添加了一些关于我的用例的信息,也许现在我的用例更清楚了

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


【解决方案1】:

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

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

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

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

解决空指针“问题”的正确方法(这并不是真正的问题,它只是 C(以及 C++)的一个方面,如果没有适当的解决方案,可能会使代码难以维护care/documentation) 是以某种方式将Index 暴露为不透明类型;例如

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

【讨论】:

  • 我同意你的观点,但我的用例是包装一个 C 库,所以我不能在我的公共头文件中使用类(这就是使用 void* 的原因)
  • 在 C 下运行时仍然可以创建一个 dummy struct,例如:#ifndef __cplusplus typedef struct IndexCDummy Index。我过去使用过这种方法——它确保了用户类型的安全。在这种情况下,IndexCDummy 从未在任何地方定义,但它确实使编译器知道这个类型化的不透明指针。我会把这个放在我的答案中,但它会使答案与它的立场大不相同
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-07
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2013-12-25
    • 2011-06-17
    相关资源
    最近更新 更多