2013-05-13 95 views
0

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)

+1

what.c执行two.c? – Magn3s1um 2013-05-13 15:50:06

+0

我认为你的链接器变得困惑。我不认为实际上有3种方法命名为相同的东西,即使它们有不同的参数。我认为你的目标代码将会调用其中一个函数,而不是全部3.我认为函数1正在调用,然后其余的是函数2调用。 – Magn3s1um 2013-05-13 15:52:45

+0

会有不确定的结果,如果你这样做: http://stackoverflow.com/questions/3098380/how-to-deal-with-duplicated-function-name-within-c – Magn3s1um 2013-05-13 15:53:50

回答

0

如果你想知道到底发生了什么,有GCC输出main.o装配和看看到底发生了什么。我想你会发现,当你调用sq()时,参数被加载到你的机器上的基址寄存器中,然后sq(int i)将在第一个寄存器上执行乘法指令。如果你传递额外的参数,它们不会有任何影响,并且如果你没有传递任何参数,它只会处理先前加载到该寄存器中的任何值。

0

所以,我之前根据我在帖子中阅读的内容写了一个答案。哪一个错了。这是正确的答案。

zero.c不会生成任何代码。 two.c不会生成任何代码。

main.c和one.c是实际生成代码的唯一文件。在one.c中调用一个参数为sq(int i)的函数,其中没有参数是未定义的行为(所以“任何事情都可能发生”,包括与某些情况类似的东西)。用两个参数调用也是未定义的行为 - 同样,当你这样做时,它不一定会“出错”,但是你不能保证工作(或者做你期望的) - 例如它可以返回9,因为它将参数从最后一个记录到第一个记录。

+0

不同意...只有1个定义。 zero.c&two.c只是原型。 – anishsane 2013-05-13 16:24:52

+0

啊,啊。好的,将编辑。 – 2013-05-13 16:28:25

0

zero.c & two.c没有任何函数定义。这只是原型声明。因此,它不会创建任何具有函数定义的汇编代码。 (提示:用gcc -s标志进行编译验证。)

只有two.c有函数定义。因此,two.s将有一个函数sq,该函数接受第一个参数(通常在堆栈或处理器的第一个寄存器上传递,如intel上的eax或arm中的r0)&返回其正方形。

由于您在main.c中没有给出任何原型,所以编译器(.c - > .s)不会抱怨。它可能可能将其视为int sq(...),但我不确定它。

因此,对于3个不同的输入: sq()sq(2)sq(2,3)将所有呼叫到相同的功能,这是在two.c.声明

现在,输出为sq(2) & sq(2,3)是显而易见的 - 通过第一个参数的返回平方。 sq()的输出将取决于在堆栈中看到的堆栈/ eax/r0上的内容。似乎它是1.提示:在gdb下运行来验证。

+0

'zero.c'没有任何原型,只是一个声明。 – effeffe 2013-05-13 16:51:12

+0

我曾经习惯于使用术语原型&intercarable ...可以告诉我区别吗? – anishsane 2013-05-13 17:09:57

+0

原型是带参数列表的函数声明。 'foo()'并不意味着'foo'没有参数,但它可以接受任意类型的任意数量的参数(没有使用它们,因为没有参数)。在C中没有参数的函数的原型看起来像'foo(void)',你可以在这里找到关于这个区别的一些问题。 – effeffe 2013-05-13 17:16:55

0

按照C时的参数,你的代码调用多种方式未定义行为(可能更多):

在同一范围内的同一功能的
  • 两个声明使用不同的回报或者参数类型/计数
  • 对于没有函数原型范围的函数的调用,参数的个数不等于参数

由于这是不确定的行为的数量,你没有办法预测会发生什么。结果甚至不一定必须是一致的。如果您没有看到此代码的编译时警告/错误,那么您需要调高编译器的警告级别。

在main.c中添加原型可能会用此代码解决编译器的警告。不过,链接器可能仍然存在问题,因为在同一范围内有多个具有相同名称的函数,并且不清楚您希望代码使用哪一个函数。