【代码技巧】【C语言】鸿蒙 openHarmony 代码中的“多态”

  1. OsArmA32SyscallHandle
    当不同消息ID对应不同的处理函数时,c语言可以抽象函数指针,来归一化处理
    假如需要不同入参的处理函数时,鸿蒙的系统调用提供了另一种方法。
    源码链接
VOID OsArmA32SyscallHandle(TaskContext *regs)
{
    UINT32 ret;
    UINT8 nArgs;
    UINTPTR handle;
    UINT32 cmd = regs->reserved2;

    if (cmd >= SYS_CALL_NUM) {
        PRINT_ERR("Syscall ID: error %d !!!\n", cmd);
        return;
    }

    handle = g_syscallHandle[cmd];
    nArgs = g_syscallNArgs[cmd / NARG_PER_BYTE]; /* 4bit per nargs */
    nArgs = (cmd & 1) ? (nArgs >> NARG_BITS) : (nArgs & NARG_MASK);
    if ((handle == 0) || (nArgs > ARG_NUM_7)) {
        PRINT_ERR("Unsupported syscall ID: %d nArgs: %d\n", cmd, nArgs);
        regs->R0 = -ENOSYS;
        return;
    }

    OsSigIntLock();
    switch (nArgs) {
        case ARG_NUM_0:
        case ARG_NUM_1:
            ret = (*(SyscallFun1)handle)(regs->R0);		// 为何0入参的函数可以这样调用
            break;
        case ARG_NUM_2:
        case ARG_NUM_3:
            ret = (*(SyscallFun3)handle)(regs->R0, regs->R1, regs->R2);		// 同上 同下?? why
            break;
        case ARG_NUM_4:
        case ARG_NUM_5:
            ret = (*(SyscallFun5)handle)(regs->R0, regs->R1, regs->R2, regs->R3, regs->R4);		
            break;
        default:
            ret = (*(SyscallFun7)handle)(regs->R0, regs->R1, regs->R2, regs->R3, regs->R4, regs->R5, regs->R6);
    }

    regs->R0 = ret;
    OsSigIntUnlock();

    return;
}

上图中的系统调用有0~7个接口的情况,代码通过01、23、45、67来进行区分调用,
问题1:0和1时、2和3时入参个数不一样,为何能够编译通过??
问题2:函数调用为何能正常工作??

下边是我的理解
问题1:因为(*(SyscallFun1)handle)的强转将handle转化为了有一个入参的函数,所以就算handle对应SyscallFun0的类型,也不会编译报错
问题2:函数调用前,会将指定的入参入栈,在函数执行中,去栈中取所需的入参,因此,当handle是SyscallFun0的类型时,虽然regs->R0已经在栈中了,但是handle执行中并不会去使用它。
那么问题又来了,顺着这种思路,case就不需要区分了, 统一按照最长入参个数的函数类型来调用即可。
验证:

#include <stdio.h>
typedef unsigned int UINT32;
typedef UINT32 (*SyscallFun3)(UINT32, UINT32, UINT32);
typedef UINT32 (*SyscallFun2)(UINT32, UINT32);
typedef UINT32 (*SyscallFun1)(UINT32);
typedef UINT32 (*SyscallFun0)();
UINT32 fun0()
{
	printf("%s \n", __FUNCTION__);
}
UINT32 fun1(UINT32 a)
{
	printf("%s %d\n", __FUNCTION__, a);
}
UINT32 fun2(UINT32 a, UINT32 b)
{
	printf("%s %d %d \n", __FUNCTION__, a, b);
}
UINT32 fun3(UINT32 a, UINT32 b, UINT32 c)
{
	printf("%s %d %d %d\n", __FUNCTION__, a, b, c);
}
UINT32 *pArr[4] = {
	(UINT32 *)fun0,
	(UINT32 *)fun1,
	(UINT32 *)fun2,
	(UINT32 *)fun3,
};

int test(UINT32 nArgs)
{
	UINT32 * pFun = pArr[nArgs];
	switch (nArgs) {
		case 0:
		case 1:
		case 2:
		case 3:
			((SyscallFun3)pFun)(nArgs, nArgs, nArgs);	// 去掉switch 仅保留该句也是可行的
			break;
	}
}

int main()
{
   printf("Hello, World! \n");
   test(0);
   test(1);
   test(2);
   test(3);
   return 0;
}

实际输出:推荐一个在线C语言工具
Hello, World!
fun0
fun1 1
fun2 2 2
fun3 3 3 3

至于为何鸿蒙代码没有这样实现,应该是出于节省栈空间的考虑,毕竟连g_syscallNArgs这种变量都能省则省,8bit的数据拆成2个4bit来用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,我很乐意为您提供代码实例。 JAVA实现多态的一个常见方式是使用类的继承和方法的重写。具体来说,定义一个父类并在其定义一个或多个方法,然后在其子类重写这些方法以实现不同的行为,就可以实现多态代码示例如下: ``` class Animal { public void makeSound() { System.out.println("Animal is making a sound."); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("Meow!"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Woof!"); } } public class Test { public static void main(String[] args) { Animal animal1 = new Cat(); Animal animal2 = new Dog(); animal1.makeSound(); // 输出 "Meow!" animal2.makeSound(); // 输出 "Woof!" } } ``` 在这个例子,我们定义了一个名为“Animal”的父类,其包含了一个名为“makeSound”的成员方法。我们还定义了两个子类“Cat”和“Dog”,它们分别重写了父类的“makeSound”方法并实现了不同的行为。在主方法,我们定义了两个Animal类型的变量,并通过实例化Cat和Dog对象分别赋值,然后调用它们的“makeSound”方法。由于Cat和Dog都扩展了Animal,因此它们被视为Animal类型的对象,并且可以随时被赋值给Animal类型的变量。这也就是JAVA实现多态的方式之一,通过方法重写和运行时类型信息的特性,可以实现不同类型的对象(尽管它们有不同的子类型)在调用相同的方法时产生不同的行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值