功能已被引用..但是在哪里? [英] Function already referenced .. but where?

查看:57
本文介绍了功能已被引用..但是在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我有一个已经创建的数学函数的头文件,我想在class1.cpp中使用它.如果不包含它,则会出现以下错误:

Hey guys,

I have a header file of math functions I''ve created and I want to use it in class1.cpp. When I don''t include it I get the following errors:

1>Output.cpp(465): error C3861: 'createRot': identifier not found
1>Output.cpp(471): error C3861: 'createRot': identifier not found
1>Output.cpp(477): error C3861: 'createRot': identifier not found



但是当我包含头文件时,出现以下错误:



but when I include the header file I get the following errors:

1>RTClientExample.obj : error LNK2005: "double * __cdecl crossProd(double * const,double * const)" (?crossProd@@YAPANQAN0@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl createTrans(double * const,double (*)[3],double (*)[4])" (?createTrans@@YAXQANPAY02NPAY03N@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl createRot(double * const,double * const,double * const,double (*)[3])" (?createRot@@YAXQAN00PAY02N@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl rotVect(double *,double (*)[3],double * const)" (?rotVect@@YAXPANPAY02NQAN@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl transpose(double (*)[3])" (?transpose@@YAXPAY02N@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl matMult(double (*)[3],double (*)[3],double (*)[3])" (?matMult@@YAXPAY02N00@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl matMult(double * const,double (*)[3],double *)" (?matMult@@YAXQANPAY02NPAN@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl angle(double * const,double * const,double *)" (?angle@@YAXQAN0PAN@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "int __cdecl round(double)" (?round@@YAHN@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl printTrans(double (*)[4])" (?printTrans@@YAXPAY03N@Z) already defined in Output.obj
1>RTClientExample.obj : error LNK2005: "void __cdecl printRot(double (*)[3])" (?printRot@@YAXPAY02N@Z) already defined in Output.obj


各位女士和女士们可以看到,在这种情况下,它告诉我它已经在class1.obj
中定义
我确定这是一个愚蠢的错误,但我不太确定该错误可能是什么.有人可以帮我清理一下吗?最后要说明的是,我之前曾使用过该文件,并且可以正常工作.

Don



As you ladies and gentlemen can see, in this case it tells me that it''s already defined in class1.obj

I''m sure it''s a dumb mistake but I''m not really sure what that mistake may be. Could someone clear this up for me? As a final note, I have used this file before and it works just fine.

Don

推荐答案

看起来就像您在标头中定义了函数.例如,如下所示:
Looks like you defined the functions right in your header. For example, like this:
// file foo.h
void foo() {
   puts "Hello World!");
}


// file foo.cpp
#include "foo.h"


//file bar.cpp
#include "foo.h"


请注意,#include是一个预处理程序命令,使预处理程序将foo.h中包含的整个文本复制到每个包含它的cpp文件中,因此,在完成prprocessor之后,您得到的中间cpp文件如下所示:


Note that #include is a preprocessor command, causing the preprocessor to copy the whole text contained in foo.h into each of the cpp file including it, so, after the prprocessor is done, the intermediate cpp files that you get look like this:

// file foo.cpp after preprocessor step
void foo() {
   puts("Hello World!");
}


// file bar.cpp after preprocessor step
void foo() {
   puts("Hello World!");
}


现在,编译器将使用foo.cpp的处理后的版本,查找带有签名void foo()的函数,并存储该函数的签名以及其启动的二进制代码的地址.然后,编译器选择bar.cpp的处理后的版本,然后执行相同的操作,而忽略了进入foo.obj的代码(不,编译器不会跟踪其他已编译的模块!).

然后,链接器逐步启动,并将所有模块绑定到一个可执行文件中.为此,它需要创建一个包含所有功能的表,以及在二进制代码中这些功能开始处的内存偏移量.它拾取foo,obj并使用签名void foo()注册该函数.然后,它选择bar.obj并尝试在该处注册找到的函数foo(),但会注意到通过该签名的函数已经存在!由于链接器不知道二进制文件的两个版本是否相同,并且不清楚要调用哪个函数,因此链接器本身无法解决此问题.因此,它发出错误LNK2005.

有一些例外:如果将函数定义为inline,则预处理器不会将整个函数放入包含标头的源文件中,而是将所有对函数的调用替换为函数体的代码,很像#define宏(但更安全).似乎也可以在声明它们的位置定义类的成员函数,尽管我不确定这是否是由于将它们解释为内联函数,还是不确定函数代码形式类是否被不同对待. />
简而言之,您不应该在头文件中定义函数!头文件仅用于声明.


Now the compiler takes the processed version of foo.cpp, finds the function with the signature void foo(), and stores the signature of this function as well as the address of the binary code that it starts. Then the compiler picks the processed version of bar.cpp and does the same, ignorant of the code that went into foo.obj (no, the compiler does not keep track of other compiled modules!).

Then the linker steps up, and binds all modules into one executable. To do so it needs to create a table of all functions and the memory offsets to the start of these functions within the binary code. It picks up foo,obj and registers the function with the signature void foo(). Then it picks up bar.obj and tries to register the function foo() it finds there, but notices that a function by that signature already exists! Since the linker does not know whether the two versions of the binaries are identical, and it isn''t clear which function to call, the linker, by itself cannot resolve this issue. Hence it issues the error, LNK2005.

There are a few exceptions: If you define a function as inline, then the preprocessor will not put the whole function into the source file that include the header, but instead will replace all calls to the function with the code of the functions body, much like a #define macro (but a lot safer). It also seems that defining member functions of a class right at the point where they are declared is also possible, although I am not sure if this is due to them being interpreted as inline, or whether functional code form classes is treated differently.

In short, you should not define functions in a header file! A header file is meant for declarations only. Move the definitions to a separate cpp file instead and your problem should be solved.


请注意:第一个错误来自编译器,第二个错误来自链接器;第二个错误来自链接器;第二个错误来自链接器.和符号是不同的.这意味着您尝试两次链接相同的符号:一次是您要链接(之前已编译)的某个库或目标文件,另一次是您在构建期间编译的目标文件中.
使用一些二进制转储和/或文档来查看在哪些库(例如DUMPBIN.EXE)上定义了哪些符号.该实用程序与所有版本的Visual Studio捆绑在一起,可以通过Visual Studio命令提示符运行,请参见此处的参考: http://en.wikipedia.org/wiki/Include_guard [^ ].但是,我认为问题出在使用您的库中.

—SA
Pay attention: first bunch of errors from compiler, but second one from the linker; and the symbols are different. It means that you try to link in the same symbol(s) twice: once is some library or object file you''re linking in (compiled before), another time in the object file which you compile during build.

Use some binary dump and/or documentation to see what symbols are defined on what libraries, such as DUMPBIN.EXE. This utility is bundled with all versions of Visual Studio and can be run via Visual Studio Command Prompt, see the reference here: http://msdn.microsoft.com/en-us/library/c1h23y6c%28v=vs.71%29.aspx[^].

Just in case, make sure you always use proper include guards in all your include files, see http://en.wikipedia.org/wiki/Include_guard[^]. However, I think the problem is in using your library.

—SA


尽管不建议使用....一种快速解决方法是

如果您使用的是Visual Studio,

转到 ProjectProperties-> ConfigurationProperties->链接器->命令行

将以下行添加到其他选项

Though it is not recommended .... one quick fix is

if you are using Visual studio,

Go to ProjectProperties->ConfigurationProperties->Linker->Command Line

Add following line to the Additional Options

/FORCE




此选项将强制链接器采用可用的定义之一.




This option will force the linker to take one of the available definitions.


这篇关于功能已被引用..但是在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆