zero.c:
int sq();
one.c:
int sq(int i) { return i*i; }
two.c:
int sq(int i, int j);
main.c中:
int main() {
printf("%d\n",sq());
printf("%d\n",sq(2));
printf("%d\n",sq(2,3));
}
然后我单独编译每个文件并gcc zero.o one.o two.o main.o -o main
./main
给出了
1
4
4
我有点困惑,因为它如何成功运作。当我致电sq()
或sq(2)
或sq(2,3)
答案 0 :(得分:0)
如果你想知道究竟发生了什么,请让gcc输出main.o的程序集并查看。我想你会发现当你调用sq()时,参数被加载到你机器上的基本寄存器中,然后sq(int i)将在第一个寄存器上执行乘法指令。如果你传递额外的参数,它们将没有任何影响,如果你没有传递任何参数,它将只适用于先前加载到该寄存器中的任何值。
答案 1 :(得分:0)
所以,我之前根据我在帖子中读到的内容写了一个答案。这是错的。这是正确的答案。
zero.c不会生成任何代码。 two.c不生成任何代码。
main.c和one.c是实际生成代码的唯一文件。
在one.c中调用一个参数sq(int i)
,没有参数的函数是未定义的行为(所以“任何事情都可能发生”,包括类似于你在某些情况下的预期)。使用两个参数调用也是未定义的行为 - 再次,当你这样做时它不一定会“出错”,但你不能保证它能够工作(或做你期望的事情) - 例如它也可以返回9因为它将参数从最后一个放到第一个寄存器中。
答案 2 :(得分:0)
zero.c& two.c没有任何函数定义。它只是原型声明。因此,它不会创建任何具有函数定义的汇编代码。 (提示:使用gcc -s
标志进行编译以进行验证。)
只有two.c有函数定义。因此,two.s将具有函数sq
,它接受第一个参数(通常在堆栈或处理器的第一个寄存器上传递,如英特尔上的eax或手臂中的r0)&返回它的方格。
由于你没有在main.c中给出任何原型,编译器(.c - > .s)不会抱怨。它可能可能将其视为int sq(...)
,但我不确定。
因此,对于3种不同的输入:
sq()
,sq(2)
,sq(2,3)
将调用同一个函数,该函数在two.c中声明。
现在,sq(2)
&的输出sq(2,3)
很明显 - 返回第一个参数的平方。 sq()
的输出将取决于sq / stack中堆栈/ eax / r0上的内容。似乎是1.提示:在gdb下运行以验证。
答案 3 :(得分:0)
根据C规范,您的代码以多种方式(可能更多)调用未定义的行为:
由于这是未定义的行为,因此您无法预测会发生什么。结果甚至不一定必须一致。如果您没有看到此代码的编译时警告/错误,那么您需要调高编译器的警告级别。
在main.c中添加原型可能会使用此代码解决编译器的警告。但是,链接器可能仍然存在问题,因为在同一范围内有多个具有相同名称的函数,并且不清楚您希望代码使用哪个函数。