在阅读头文件时,经常会发现如下类似的代码。当你想要查找具体的结构体定义,发现没有任何地方出现了该定义。你甚至会怀疑自己的头文件是否齐全。
struct nvgraphContext;
typedef struct nvgraphContext *nvgraphHandle_t;
typedef struct CUstream_st *CUstream;
typedef __device_builtin__ struct CUstream_st *cudaStream_t;
这种称为不透明指针,一般出现在闭源代码中,用于隐藏结构体的具体定义。是一种特别常用的技巧。
假设有头文件 header.cpp 中有如下定义:
struct context;
typedef struct context* context_t;
void setContext(context_t ctx, context_t ctx2) {
ctx = ctx2;
}
为什么这样的场景不会出错?一般在编译器生成代码的时候,需要知道结构体的大小,但是如果我们在使用过程中,不访问其内部变量,就可以将 context_t 作为一个void *
使用,void* 就是一个不完整类型(incomplete type),void* 的大小是固定的,编译器就能够正常处理。
注意,如果按照如下方式,声明一个栈变量,是会报错的。
context ctx;
是因为,此时编译器需要知道 context的大小,但是context此时是不完整类型,大小是未知的。
struct context {
int length;
};
void setLength(context_t ctx, int len) {
ctx->length = len;
}
int main() {
context_t ctx = new context;
setLength(ctx, 10);
return 0;
}
如果此时不提供结构体的具体定义时,就会出现如下错误:
error: invalid use of incomplete type ‘struct context’
12 | ctx->length = len;