为您的c++库提供一个C API,并提供严格的别名

时间:2022-09-13 08:05:39

A common pattern when providing a C API is to forward declare some opaque types in your public header which are passed to your API methods and then reinterpret_cast them into your defined C++ types once inside the translation unit (and therefore back in C++ land).

在提供C API时,一个常见的模式是在公共标头中转发一些不透明的类型,这些类型被传递给API方法,然后在转换单元中(因此在c++ land中)将它们重新转换为定义的c++类型。

Using LLVM as an example:

In Types.h this typedef is declared:

在类型。h此类型定义声明:

typedef struct LLVMOpaqueContext *LLVMContextRef;

LLVMOpaqueContext is not referenced anywhere else in the project.

项目中的其他地方没有引用LLVMOpaqueContext。

In Core.h the following method is declared:

在核心。h申报方法如下:

LLVMContextRef LLVMContextCreate(void);

Which is defined in Core.cpp:

在Core.cpp中定义:

LLVMContextRef LLVMContextCreate() {
  return wrap(new LLVMContext());
}

wrap (and unwrap) is defined by a macro in CBindingWrapping.h:

wrap(和unwrap)是由cbindingwrappapp中的宏定义的。h:

#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)     \
  inline ty *unwrap(ref P) {                            \
    return reinterpret_cast<ty*>(P);                    \
  }                                                     \
                                                        \
  inline ref wrap(const ty *P) {                        \
    return reinterpret_cast<ref>(const_cast<ty*>(P));   \
}

And used in LLVMContext.h:

和用于LLVMContext.h:

DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef)

So we see that the C API basically takes a pointer to an LLVMOpaqueContext and casts it into an llvm::LLVMContext object to perform whatever method is called on it.

因此,我们看到C API基本上接受指向LLVMOpaqueContext的指针,并将其转换为llvm::LLVMContext对象,以执行调用它的任何方法。

My question is: isn't this in violation of the strict aliasing rules? If not, why not? And if so, how can this type of abstraction at the public interface boundary be acheived legally?

我的问题是:这是不是违反了严格的混叠规则?如果没有,为什么不呢?如果是这样,如何在公共接口边界上实现这种类型的抽象呢?

1 个解决方案

#1


22  

It's not a strict aliasing violation. To start with, strict aliasing is about accessing an object via a glvalue of the wrong type.

这不是一个严格的假混。首先,严格的别名是通过错误类型的glvalue访问对象。

In your question, you create a LLVMContext, and then use a LLVMContext lvalue to access it. No illegal aliasing there.

在您的问题中,您创建了一个LLVMContext,然后使用一个LLVMContext lvalue来访问它。没有违法的混叠。

The only issue which may arise is if the the pointer conversion doesn't yield back the same pointer. But that too is not a problem, since reinterpret_cast is guaranteed to give back the same pointer in a round-trip conversion. So long as the pointer type we convert to and back from is to suitably aligned data (i.e. not stricter than the original type).

唯一可能出现的问题是,如果指针转换不返回相同的指针。但这也不是问题,因为reinterpretation t_cast保证在往返转换中返回相同的指针。只要我们将指针类型转换为和返回到适当对齐的数据(即不比原始类型更严格)。

Whether or not it's a good or bad way to go about things is debatable. I personally would not bother with LLVMOpaqueContext and return a struct LLVMContext*. It's still an opaque pointer, and it doesn't matter that the C header declares it with struct while the type definition is with class. The two are interchangeable up to the point of the type definition.

这到底是好是坏,还有待商榷。我个人不会费心使用LLVMOpaqueContext并返回一个struct LLVMContext*。它仍然是一个不透明的指针,而且C头使用struct声明它,而类型定义使用类并不重要。这两个可以互换到类型定义的点。

#1


22  

It's not a strict aliasing violation. To start with, strict aliasing is about accessing an object via a glvalue of the wrong type.

这不是一个严格的假混。首先,严格的别名是通过错误类型的glvalue访问对象。

In your question, you create a LLVMContext, and then use a LLVMContext lvalue to access it. No illegal aliasing there.

在您的问题中,您创建了一个LLVMContext,然后使用一个LLVMContext lvalue来访问它。没有违法的混叠。

The only issue which may arise is if the the pointer conversion doesn't yield back the same pointer. But that too is not a problem, since reinterpret_cast is guaranteed to give back the same pointer in a round-trip conversion. So long as the pointer type we convert to and back from is to suitably aligned data (i.e. not stricter than the original type).

唯一可能出现的问题是,如果指针转换不返回相同的指针。但这也不是问题,因为reinterpretation t_cast保证在往返转换中返回相同的指针。只要我们将指针类型转换为和返回到适当对齐的数据(即不比原始类型更严格)。

Whether or not it's a good or bad way to go about things is debatable. I personally would not bother with LLVMOpaqueContext and return a struct LLVMContext*. It's still an opaque pointer, and it doesn't matter that the C header declares it with struct while the type definition is with class. The two are interchangeable up to the point of the type definition.

这到底是好是坏,还有待商榷。我个人不会费心使用LLVMOpaqueContext并返回一个struct LLVMContext*。它仍然是一个不透明的指针,而且C头使用struct声明它,而类型定义使用类并不重要。这两个可以互换到类型定义的点。