Sam*_*ett 25 c c++ llvm strict-aliasing
提供C API时的一个常见模式是在公共头中转发声明一些不透明的类型,这些类型传递给您的API方法,然后reinterpret_cast在翻译单元内转换为定义的C++类型(因此返回C++版本).
在Types.h中,声明了这个typedef:
typedef struct LLVMOpaqueContext *LLVMContextRef;
Run Code Online (Sandbox Code Playgroud)
LLVMOpaqueContext 未在项目中的任何其他位置引用.
在Core.h中,声明了以下方法:
LLVMContextRef LLVMContextCreate(void);
Run Code Online (Sandbox Code Playgroud)
这是在Core.cpp中定义的:
LLVMContextRef LLVMContextCreate() {
return wrap(new LLVMContext());
}
Run Code Online (Sandbox Code Playgroud)
wrap(和unwrap)由CBindingWrapping.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)); \
}
Run Code Online (Sandbox Code Playgroud)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef)
Run Code Online (Sandbox Code Playgroud)
所以我们看到C API基本上接受一个指针LLVMOpaqueContext并将其转换为一个llvm::LLVMContext对象,以执行在其上调用的任何方法.
我的问题是:这不违反严格的别名规则吗?如果没有,为什么不呢?如果是这样,那么在公共接口边界上的这种抽象如何能够合法地实现呢?
Sto*_*ica 22
这不是严格的别名违规.首先,严格别名是通过错误类型的glvalue访问对象.
在您的问题中,您创建一个LLVMContext,然后使用LLVMContext左值来访问它.那里没有非法走样.
可能出现的唯一问题是指针转换是否不会返回相同的指针.但这也不是问题,因为reinterpret_cast保证在往返转换中返回相同的指针.只要我们转换为和返回的指针类型是适当对齐的数据(即不比原始类型更严格).
无论是好事还是坏事都是值得商榷的.我个人不会打扰LLVMOpaqueContext并返回struct LLVMContext*.它仍然是一个不透明的指针,并且struct在类型定义为的时候C头声明它并不重要class.这两者可以互换,直到类型定义.