函数
FunC 程序本质上是一系列函数声明/定义和全局变量声明。本节涵盖了第一个主题。
任何函数声明或定义都以一个共同的模式开始,接下来有三种情况之一:
-
单个
;
,表示函数已声明但尚未定义。它可能会在同一文件中的后面或在传递给 FunC 编译器的其他文件中定义。例如,int add(int x, int y);
是一个名为
add
类型为(int, int) -> int
的函数的简单声明。 -
汇编函数体定义。这是通过低层级 TVM 原语定义函数以便在 FunC 程序中后续使用的方法。例如,
int add(int x, int y) asm "ADD";
是同一个
add
函数的汇编定义,类型为(int, int) -> int
,将转换为 TVM 操作码ADD
。 -
常规块语句函数体定义。这是定义函数的常用方式。例如,
int add(int x, int y) {
return x + y;
}是
add
函数的常规定义。
函数声明
如前所述,任何函数声明或定义都以一个共同的模式开始。以下是该模式:
[<forall declarator>] <return_type> <function_name>(<comma_separated_function_args>) <specifiers>
其中 [ ... ]
对应于可选条目。
函数名
函数名可以是任何标识符,也可以以 .
或 ~
符号开头。这些符号的含义在声明部分解释。
例如,udict_add_builder?
、dict_set
和 ~dict_set
都是有效且不同的函数名。(它们在 stdlib.fc 中定义。)
特殊函数名
FunC(实际上是 Fift 汇编器)有几个预定义的保留函数名,具有预定义的id。
main
和recv_internal
的 id 为 0recv_external
的 id 为 -1run_ticktock
的 id 为 -2
每个程序必须有一个 id 为 0 的函数,即 main
或 recv_internal
函数。
run_ticktock
在特殊智能合约的 ticktock 交易中被调用。
接收内部消息
recv_internal
在智能合约接收到内部入站消息时被调用。
当 TVM 初始化 时,栈上有一些变量,通过在 recv_internal
中设置参数,我们使智能合约代码能够了解其中的一些变量。那些代码不知道的变量将永远躺在栈底,从未被触及。
因此,以下每个 recv_internal
声明都是正确的,但具有较少变量的声明将稍微节省一些gas(每个未使用的参数都会增加额外的 DROP
指令)
() recv_internal(int balance, int msg_value, cell in_msg_cell, slice in_msg) {}
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) {}
() recv_internal(cell in_msg_cell, slice in_msg) {}
() recv_internal(slice in_msg) {}