使用 ABAP Development Tool 的源代码搜索功能,搜索关键字 %_c_pointer, 能搜出很多结果:
具有这种百分号开头的数据类型的 ABAP 变量,无一例无的都用于 ABAP 框架实现里,并且均参与了 System Call 或者 Kernel Module 调用。
关于 ABAP System Call 和 Kernel Module 调用,请参阅笔者之前的文章:
所以 %_c_pointer 到底描述了何种数据类型?
或许我们可以从一个定义了该类型的 ABAP 类属性的描述信息里,挖掘一点端倪:Decompress Handle.
Handle 是计算机编程领域里使用及其广泛的一个术语,中文翻译成句柄。
计算机系统在程序设计中涉及多种硬件和软件资源,例如文件、内存块、图形对象、进程线程等。
这些资源既需访问,也需有效管理。然而,这些资源的管理往往相当复杂且易出错,因为它们直接关联底层的物理或逻辑组件,例如磁盘的特定扇区或者内存的某个地址空间。
为了处理这种复杂性,handle 作为一个中间层次的抽象角色,为资源管理和使用带来了极大的简化。
Handle 本质上是一个抽象引用,作为一种间接的标识符,用于让操作系统或运行时环境,找到真实资源的引用。当程序想要操作某一特定资源时,它通过 handle 向操作系统或者管理资源的 API 发出请求,操作系统或者 API 负责管理资源的细节。
比如上图 CL_ABAP_UNGZIP_BINARY_STREAM 类,负责对二进制流进行解压操作。句柄 DS 指向待操作的二进制流,配合其方法 DECOMPRESS_BINARY_STREAM 对这些流进行解压操作。
通过抽象的句柄,为 ABAP 开发人员屏蔽了流的底层存储方式和操作手段等技术实现细节。
同样,%_c_pointer 名称里带有的 pointer,让我们不禁思考,是否这个类型同 C 语言的指针有某种联系?
实际上,它就是 C 语言里一种特殊类型的指针,即指向指针的指针。
我们在 ABAP 帮助文档里进行搜索,就可以找到 ABAP 数据类型 %_c_pointer 在 C 语言里的对应类型:void**.
从上图这张表里,大家还能发现 ABAP 泛型编程里常用的 DATA,ANY, SIMPLE 等数据类型,对应着 C 语言里的 void*.
那么 void, void* 和 %_c_pointer 对应的 void**, 各自的含义是什么?
void 是 C 语言中的一种特殊类型,表示无类型或无返回值。
void 具有多种用途,其语义在不同上下文中会有所变化。
用作函数的返回类型:表示该函数不返回任何值。例如
void printMessage() {
printf("Hello, World!\n");
}
相当于 ABAP Function Module 没有定义 EXPORTING 或者 RETURNING 参数。
void 告诉编译器,这个函数只执行某种操作,而不需要返回数据。
用作函数的参数列表:当函数的参数部分定义为 void 时,表示该函数不接受任何参数。例如:
void doSomething(void) {
// 这里的代码不需要任何输入参数
}
相当于 ABAP Function Module 里没有定义任何 IMPORTING 或者 CHANGING 参数。
void* 是 C 语言中的通用指针或无类型指针。
它可以指向任何数据类型,而不要求明确指明所指向的数据类型。
例如开发人员可以将 int,float,或者 struct 的地址赋值给一个 void* 类型的指针。
int a = 10;
void* p = &a; // void* 指向一个 int 类型的数据
void* 在 C 语言中有着重要的地位,尤其是在实现通用的函数库或处理不同类型的数据时。例如,标准库函数 malloc 使用 void* 返回指向新分配内存的指针:
void* ptr = malloc(100); // 分配 100 字节的内存
在这种场景下,malloc 不知道调用者希望将这块内存用于哪种类型的数据,因此它返回一个 void*.
调用者可以根据需要将这个指针转换为其他具体类型的指针。
因此有 C 语言使用 void* 基础的开发人员,转 ABAP 开发时,对于 DATA,ANY 等关键字的理解,可以说是轻松愉快。
void** 是一个指向 void* 类型数据的指针,也就是说,它是指向指针的指针,即多级指针。
以下是一个例子:
int a = 10;
void* p = &a; // p 是一个 void*,指向 int 类型的数据
void** pp = &p; // pp 是一个 void**,指向 p
在这个例子中,pp 是一个指向 p 的指针。而 p 本身是一个 void*,指向整数 a.
因此,void** 实际上是用来间接访问某个指针的。
这可以类比为一份地图。假设地图 pp 指向另一份地图 p,而 p 最终指向目标地点 a.
void** 就是这样的地图,提供一种间接查找最终地址的能力。
可以用下面的 ABAP 代码来近似模拟 C 语言里多级指针的例子。
DATA: lv_i TYPE int4 VALUE 1.
DATA(void*) = REF
DATA(void**) = REF
WRITE: void**->*->*.
这里的变量 void*, 是一个指向整数 1 的引用,而变量 void**, 是指向该引用的引用。
ABAP 里的引用变量和 Field Symbol 结合起来,实现了 C 语言里指针的功能。
下图中的代码显示,* 也是 ABAP 变量名的一部分,这种命名方式合法,但是并不推荐,因为会给代码阅读者带来不必要的麻烦。
笔者在之前的文章里有详细介绍:
那些令人哭笑不得,看了想揍人的 ABAP 变量命名方式,强烈不推荐
如果大家即使阅读了本文之后,对于 %_c_pointer 的含义仍然感到困惑,也没有关系。
因为这个数据类型,不会在应用层面的开发中使用到。