这是一个类似我正在处理的问题的示例代码
#include <stdio.h>
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int cube(int y){
return y*y*y;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
所以编译器给我一个未声明的多维数据集的问题。那么有人可以解释一下将这些函数放入内存的顺序等等......以及如何将原型放在顶部以及主要之后的实现有什么不同。感谢。
答案 0 :(得分:3)
存在隐式声明函数的警告,因为大多数现代C程序都不使用隐式函数。
旧C89允许隐式声明一切。当你调用一个函数时,它被隐式声明为int func ()
。
这适用于这种情况,因为您使用以下行隐式声明函数int cube()
:
x = cube(x);
然后你定义函数int cube(int)
。 int cube()
和int cube(int)
具有兼容的类型,因此这是一个很好的调用。
你真正遇到的麻烦是从一个隐式声明的函数调用一个不兼容的函数(这就是警告存在的原因)。 int cube(float)
是一个不兼容的函数类型,它肯定存在,如果你用一个隐式声明的函数调用它,你可能会期待一些非常奇怪的效果(读取未定义)。正如mafso提到的那样,严格的C99不再允许隐式声明的函数,这就是为什么许多编译器都包含警告的原因。
记住隐式声明的函数是BAD PRACTICE但你应该知道这样的场景存在。
这里有一个小程序来演示隐式声明函数的弱点。它利用了你在c程序中所期望的一些转换规则,这些规则突然消失了隐式声明的函数。
#include <stdio.h>
cube1(int x){return x*x*x;}
main(){float y = 9.; printf("%d\n%d\n", cube1(y), cube2(y));}
cube2(int x){return x*x*x;}
输出:
729
1
这些功能在asm中是相同的
00000000004004dc <cube1>:
4004dc: 55 push %rbp
4004dd: 48 89 e5 mov %rsp,%rbp
4004e0: 89 7d fc mov %edi,-0x4(%rbp)
4004e3: 8b 45 fc mov -0x4(%rbp),%eax
4004e6: 0f af 45 fc imul -0x4(%rbp),%eax
4004ea: 0f af 45 fc imul -0x4(%rbp),%eax
4004ee: 5d pop %rbp
4004ef: c3 retq
0000000000400540 <cube2>:
400540: 55 push %rbp
400541: 48 89 e5 mov %rsp,%rbp
400544: 89 7d fc mov %edi,-0x4(%rbp)
400547: 8b 45 fc mov -0x4(%rbp),%eax
40054a: 0f af 45 fc imul -0x4(%rbp),%eax
40054e: 0f af 45 fc imul -0x4(%rbp),%eax
400552: 5d pop %rbp
400553: c3 retq
但是在调用点上,从不对隐式调用执行从float到integer的预期转换。
答案 1 :(得分:1)
编译器从上到下读取文件。当它到达功能时,它会检查它是否已经知道它。在这种情况下,它没有看到函数cube(int)
,因此它返回错误。
你可以做两件事:
1.在函数cube
之前移动函数cube_then_square
。
2.您在cube_then_square
之前创建了一个前向声明:
int cube(int y);
答案 2 :(得分:1)
在文件顶部的包含下,添加int cube(int y);
您必须在使用之前声明一个函数。它不必定义,但必须在使用之前声明它,因为编译器按顺序检查行。
答案 3 :(得分:0)
要解决此问题,您可以在使用前声明cube
:
#include <stdio.h>
int cube(int y){
return y*y*y;
}
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
您还可以在顶部添加功能标题int cube(int y);
:
#include <stdio.h>
int cube(int y);
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int cube(int y){
return y*y*y;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
答案 4 :(得分:0)
这些功能如何“放入内存”完全无关紧要。实际上,这绝不会在语言层面暴露出来。没关系。
当您组织实施文件时,您可以选择以自上而下的方式或自下而上的方式进行。
在前一种情况下,首先定义上层函数。上层函数调用较低级别的函数,这些函数稍后在文件中定义。为了使其正常工作,低级函数必须在第一次调用之前另外原型化(例如在文件的最顶部)。 (形式上,不需要原型,但至少需要声明。)
在后一种情况下,首先定义低级函数,稍后定义高级函数。在这种方法中,定义本身已经作为原型,这意味着不需要额外的原型设计(除非你在函数之间有一个循环调用依赖)。
自上而下是一种更高级的维护方法,因为您必须使函数原型与其定义保持同步。
您的示例中的内容看起来像是这两种方法的混合。 main
(最高级别的函数)在底部定义,但cube_then_square
在cube
之前定义。这没有什么不妥,但为了保持这种顺序,你必须在文件的开头提供cube
的原型。
我个人更喜欢自下而上的方法。例如。在您的具体示例中,我将cube
的整个定义移到文件的顶部。这将消除提供额外原型的需要。
无论如何,无论您如何操作,生成的代码都没有任何有意义的差异。目标文件中的函数排序可能会受到源文件中的排序的影响,但从语言的角度来看,这完全是无关紧要的。