zl程序教程

您现在的位置是:首页 >  其它

当前栏目

GCC手册解析——内嵌函数(非闭包函数)

函数 解析 手册 gcc 内嵌
2023-09-14 09:13:08 时间

本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。

GCC手册解析——内嵌函数

首先强调这是GNU C的扩展,GUN C++不支持这一特性且标准C中也不支持这一特性

内嵌函数不是闭包函数,因为内嵌函数使用的scope外的变量是存储在栈上的

内嵌函数的使用

内嵌函数的定义

内嵌函数定义在一个函数或者花括号内,只要是可以定义变量的地方就可以定义内嵌函数(也可以对内嵌函数进行声明,但是需要添加auto关键字)

内嵌函数总是no linkage,所以不能使用extern或者static进行声明,如果需要声明可以使用auto关键字

//定义内嵌函数
int foo ()
{
  auto int one(); //声明内嵌函数
  int one()
  { 
  	return 1;
  }
  return one();
}

内嵌函数访问scope外的变量

内嵌函数可以访问包含它的函数 内的,且在内嵌函数定义位置处可见的全部变量,也被称为词法范围(lexical scope)

//内嵌函数访问变量
int foo (int a)
{
  int add_one(int b)
  {
	return ++b;	
  }
  return add_one(a);
}

//内嵌函数不能访问的变量
int foo (int a)
{
  int add_one(int b)
  {
	return ++b + c; //error: the c undeclared	
  }
  int c=3;
  return add_one(a);
}

内嵌函数被其它函数调用

内嵌函数可以被其它函数调用,这可以通过存储内嵌函数地址或者将内嵌函数地址作为参数传递给另一个函数,例如:

//将内嵌函数地址作为参数传递给另一个函数
typedef int(*func)();

int get_begin_index(func f)
{
	return f();
}

int foo ()
{
  int add_one()
  {
	return 1;
  }
  return get_begin_index(add_one);
}
//存储内嵌函数地址
typedef int(*func)();

func nested_func()
{
    int n=2;
    int abc()
    {
        return ++n;
    }
    return abc;
}

int main() {

    func a;
    a = nested_func();
    printf("%d\n",a());

    return 0;
}

这里我们需要强调:内嵌函数使用的scope外的变量是存储在栈上的,如果内嵌函数使用了scope外的变量且包含内嵌函数的函数已经退出,则再调用内嵌函数时会发生意想不到的结果。如果内嵌函数中没有使用任何scope外的东西则可以安全的使用

GCC通过使用“跳板”技术(trampoline)获取内嵌函数的地址
在这里插入图片描述

内嵌函数内进行Jump

内嵌函数内也可以使用goto语句,goto跳转的label需要再包含它的函数内部进行显示的声明,例如

//使用goto
int foo (int *array, int offset, int size)
{
  __label__ failure; //显示声明一个本地label
  int access (int *array, int index)
  {
    if (index > size)
      goto failure;
    return array[index + offset];
  }
  
  int i;
  /* … */
  for (i = 0; i < size; i++)
  {
    /* … */ 
    access (array, i) /* … */
    /* … */
  }
  
  return 0;

 /* Control comes here from access if it detects an error.  */
 failure:
  return -1;
}

在这里插入图片描述