我想知道C编译器(我试过gcc和clang)如何组织内部函数的参数列表。为此我做了包括以下两个文件的程序,例如:函数转换和函数参数列表的内部表示C
foo.c的:
double foo (double (*f) (void *, double), void * arg, double x)
{
return f (arg, x);
}
的main.c:
#include <stdio.h>
extern double foo (double (*) (double), double);
double bar (double x)
{
return x + x;
}
int main()
{
double x = foo (&bar, 2);
printf ("%g\n", x);
return 0;
}
,并与参数列表和身体玩foo.c中的foo
。当foo.c与main.c中的定义不一致时,程序的行为应该根据C标准来定义(如果我理解正确的话)。
我已经尝试了几种变体(包括上面的一个),用于该程序将打印4. 的更奇特的一个是
double foo (double x, double (*f) (char, double, int), int r)
{
char a;
return f (a, x, r);
}
。不过,如果我会尝试像
double foo (double x, double (*f) (char, double, double), double y)
{
char a;
return f (a, y, x);
}
结果不会是4,但如果我写f(a, x, y)
相反,我再次得到4。
该实验让我认为参数列表在内部表示为对应于不同类型的数组列表,其中关于不同类型参数顺序的信息将丢失。例如,参数列表 (char a, double x, int i, double y, char b)
将类似于(char:{a, b}, int:{i}, double:{x, y})
,并且投射到(double z, char c)
将等于(char:{c = a}, double:{z = x})
,其中我已将T:{}
定义为T
类型的数组。
所以:
我的解释是否正确?
此行为是否在某个地方标准化?
我可以依靠这样的行为多少?
此行为允许一些泛型编程。有人在实践中利用它吗?
谢谢!
这是64位或32位代码? x86和AMD64之间的调用约定有所不同 - 前者将参数从左到右传递,而后者在[各种寄存器中按类型排序]传递一些参数(http://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI) 。它是将代码打包在一起的链接器,所有这些都是处理符号加载和重定位,而不是类型。 –
@MathewHall它是x86_64,感谢您的链接。 –
@MathewHall +1实际上,Linux上的x86_64调用约定负责观察到的行为。事实上,我使用的类型是“幸运的”。通过将double切换到int来重复测试应该是一团糟。再次感谢。如果有可能,我会接受你的答案! –