C (C99) 中嵌套函数调用的限制
Limit for nested function calls in C (C99)
按照C99,函数的嵌套调用有限制吗?
示例:
result = fn1( fn2( fn3( ... fnN(parN1, parN2) ... ), par2), par1);
注意:这段代码绝对不是一个好习惯,因为很难管理;但是,此代码是从模型自动生成的,因此不存在可管理性问题。
没有。由于这些功能是一一执行的,所以没有问题。
int res;
res = fnN(parN1, parN2);
....
res = fn2(res, par2);
res = fn1(res, par1);
执行是线性的,之前的结果用于下一个函数调用。
编辑:如评论中所述,解析器 and/or 编译器可能存在问题,无法处理如此难看的代码。
如果这不是一个纯理论问题,答案很可能是"Try to rewrite your code so you don't need to do that, because the limit is more than enough for most sane use cases"。如果这纯粹是理论上的,或者您确实需要担心这个限制而不能只是重写,请继续阅读。
C11 标准的第 5.2.4 节 (latest draft, which is freely available and almost identical) 指定了对需要 支持的实现的各种限制。如果我没看错,您最多可以嵌套 63 层。
但是,允许实现支持更多,在实践中他们可能会支持。我很难找到适合 GCC 的文档(我找到的最接近的是预处理器中的表达式),但我希望它没有硬性限制,除了编译时的系统资源。
没有。没有限制。
例如,这是一个 C 代码段:
int func1(int a){return a;}
int func2(int a){return a;}
int func3(int a){return a;}
void main()
{
func1(func2(func3(16)));
}
对应的汇编代码为:
0000000000000024 <main>:
24: 55 push %rbp
25: 48 89 e5 mov %rsp,%rbp
28: bf 10 00 00 00 mov [=11=]x10,%edi
2d: e8 00 00 00 00 callq 32 <main+0xe>
32: 89 c7 mov %eax,%edi
34: e8 00 00 00 00 callq 39 <main+0x15>
39: 89 c7 mov %eax,%edi
3b: e8 00 00 00 00 callq 40 <main+0x1c>
40: 90 nop
41: 5d pop %rbp
42: c3 retq
%edi
寄存器存储每个函数的结果,%eax
寄存器存储参数。如您所见,三个 callq
指令对应三个函数调用。也就是说,这些嵌套的函数是一个一个被调用的。堆栈不用担心。
如评论中所述,当代码嵌套太深时,编译器可能会崩溃。
我写了一个简单的 Python 脚本来测试这个。
nest = 64000
funcs=""
call=""
for i in range(1, nest+1):
funcs += "int func%d(int a){return a;}\n" %i
call += "func%d(" %i
call += str(1) # parameter
call += ")" * nest + ";" # right parenthesis
content = '''
%s
void main()
{
%s
}
''' %(funcs, call)
with open("test.c", "w") as fd:
fd.write(content)
nest = 64000
可以,但是640000
会造成gcc-5.real: internal compiler error: Segmentation fault (program cc1)
.
没有直接的限制,但编译器只需要允许各种类别的一些最小限制:
来自C11 standard:
5.2.4.1 Translation limits
1 The implementation shall be able to translate and execute at least one program that contains at least one instance of every one of the following limits: 18)
...
- 63 nesting levels of parenthesized expressions within a full expression
...
- 4095 characters in a logical source line
18) Implementations should avoid imposing fixed translation limits whenever possible
按照C99,函数的嵌套调用有限制吗?
示例:
result = fn1( fn2( fn3( ... fnN(parN1, parN2) ... ), par2), par1);
注意:这段代码绝对不是一个好习惯,因为很难管理;但是,此代码是从模型自动生成的,因此不存在可管理性问题。
没有。由于这些功能是一一执行的,所以没有问题。
int res;
res = fnN(parN1, parN2);
....
res = fn2(res, par2);
res = fn1(res, par1);
执行是线性的,之前的结果用于下一个函数调用。
编辑:如评论中所述,解析器 and/or 编译器可能存在问题,无法处理如此难看的代码。
如果这不是一个纯理论问题,答案很可能是"Try to rewrite your code so you don't need to do that, because the limit is more than enough for most sane use cases"。如果这纯粹是理论上的,或者您确实需要担心这个限制而不能只是重写,请继续阅读。
C11 标准的第 5.2.4 节 (latest draft, which is freely available and almost identical) 指定了对需要 支持的实现的各种限制。如果我没看错,您最多可以嵌套 63 层。
但是,允许实现支持更多,在实践中他们可能会支持。我很难找到适合 GCC 的文档(我找到的最接近的是预处理器中的表达式),但我希望它没有硬性限制,除了编译时的系统资源。
没有。没有限制。
例如,这是一个 C 代码段:
int func1(int a){return a;}
int func2(int a){return a;}
int func3(int a){return a;}
void main()
{
func1(func2(func3(16)));
}
对应的汇编代码为:
0000000000000024 <main>:
24: 55 push %rbp
25: 48 89 e5 mov %rsp,%rbp
28: bf 10 00 00 00 mov [=11=]x10,%edi
2d: e8 00 00 00 00 callq 32 <main+0xe>
32: 89 c7 mov %eax,%edi
34: e8 00 00 00 00 callq 39 <main+0x15>
39: 89 c7 mov %eax,%edi
3b: e8 00 00 00 00 callq 40 <main+0x1c>
40: 90 nop
41: 5d pop %rbp
42: c3 retq
%edi
寄存器存储每个函数的结果,%eax
寄存器存储参数。如您所见,三个 callq
指令对应三个函数调用。也就是说,这些嵌套的函数是一个一个被调用的。堆栈不用担心。
如评论中所述,当代码嵌套太深时,编译器可能会崩溃。 我写了一个简单的 Python 脚本来测试这个。
nest = 64000
funcs=""
call=""
for i in range(1, nest+1):
funcs += "int func%d(int a){return a;}\n" %i
call += "func%d(" %i
call += str(1) # parameter
call += ")" * nest + ";" # right parenthesis
content = '''
%s
void main()
{
%s
}
''' %(funcs, call)
with open("test.c", "w") as fd:
fd.write(content)
nest = 64000
可以,但是640000
会造成gcc-5.real: internal compiler error: Segmentation fault (program cc1)
.
没有直接的限制,但编译器只需要允许各种类别的一些最小限制:
来自C11 standard:
5.2.4.1 Translation limits 1 The implementation shall be able to translate and execute at least one program that contains at least one instance of every one of the following limits: 18)
...
- 63 nesting levels of parenthesized expressions within a full expression
...
- 4095 characters in a logical source line
18) Implementations should avoid imposing fixed translation limits whenever possible