我正在尝试编译我的代码,但是当我这样做时,它会发生:
In function `main':
/home/emilio/CB/QAP/main.cpp|42|undefined reference to `start_timers()'
/home/emilio/CB/QAP/main.cpp|45|undefined reference to `elapsed_time()'
我有'timer.c'和'timer.h'作为测量时间的外部函数。
timer.c
#include <stdio.h>
#include <time.h>
#include "timer.h"
clock_t start_time;
double elapsed;
void start_timers(){
start_time = clock();
}
double elapsed_time( type )
TIMER_TYPE type;
{
elapsed = clock()- start_time;
return elapsed / CLOCKS_PER_SEC;
}
timer.h
extern clock_t start_time;
extern double elapsed;
int time_expired();
void start_timers();
double elapsed_time();
typedef enum type_timer {REAL, VIRTUAL} TIMER_TYPE;
的main.cpp
#include "timer.h"
...
double time;
start_timers();
launch_algorithm();;
time = elapsed_time();
...
我该如何解决?谢谢!
答案 0 :(得分:6)
您正在混合使用C和C ++。要在C ++文件中使用C stuff,必须像这样包装标题
#ifdef __cplusplus
extern "C"
{
#endif
extern clock_t start_time;
extern double elapsed;
int time_expired();
void start_timers();
double elapsed_time();
typedef enum type_timer {REAL, VIRTUAL} TIMER_TYPE;
#ifdef __cplusplus
}
#endif
我不确定这对您的函数有何影响,因为您还没有将参数放在头文件中的函数原型中。通常认为添加它们是最佳做法,因此如果它仍然无效,请尝试。
答案 1 :(得分:0)
所以你的理解似乎有一些漏洞,我会尽力填补空白......
主要问题是C和C ++的互操作性。
在C中有一个名为dog的函数,它接受一个int并返回void - &gt; void dog(int)
将一致地转换为目标文件,作为名为_dog
或类似名称的符号(但该符号名称由您正在使用的平台和ABI很好地定义)。
在C ++中,他们选择采用函数重载的方式还有另一层抽象。所以我们的函数void dog(int)
可以命名为_void_dog_int
或类似(这称为名称修改) ...
所以如果你想在C ++程序中使用标准的C函数,你就会有些奇怪......
在C ++程序中编写时
dog.h(某些库的接口或只是C代码)
void dog(int);
something.cpp
#include <doglib/dog.h>
void someMethod(void)
{
dog(4);
}
编译器生成一个对象,该对象期望以c ++方式命名dog(_void_dog_int
)
但是链接器在dog.o
或libdog.a
中找不到该符号或者在目标文件中找不到该符号(因为在目标文件中,符号被命名为_dog
,就像std C程序一样。 / p>
所以有一种方法告诉C ++编译器符号是C符号......构造是:
extern "C" void dog(int);
或
extern "C"
{
void dog(int);
...
}
这样可以解决我们的问题,除了它会使我们的C编译器发生错误!
因此事情必须变得更加复杂。
#ifdef __cplusplus
extern "C"
{
#endif
void dog(int);
...
#ifdef __cplusplus
}
#endif
这些宏扩展,因此在C ++中它们有一个extern“C”,在C中它们没有......
全局变量的问题是类似的... C ++和std C以不同的方式处理非限定全局变量...以支持命名空间或某些C ++构造(我没有专门研究过)
答案 2 :(得分:0)
您需要对.c
和.h
文件进行一些更改;以及extern "C"
警卫。
在timer.h中,函数声明应为:
int time_expired(void);
void start_timers(void);
double elapsed_time(TIMER_TYPE type);
在timer.c
文件中,这三行应该相同(减去分号)。
目前你拥有所谓的&#34; K&amp; R风格&#34;函数头:
double elapsed_time( type )
TIMER_TYPE type;
{
elapsed = clock()- start_time;
return elapsed / CLOCKS_PER_SEC;
}
这种函数头的问题在于它不会形成原型。如果你得到错误的参数列表,编译器在大多数情况下都不会抱怨。您只是在运行时获得未定义的行为。
通过使用原型,编译器将检查函数是否具有正确的参数数量和类型,并在必要时转换参数。
可以想象,如果函数不是原型,那么C ++编译器会出现名称错误。
NB。我在另一条评论中看到你说过#34;我改变了.c by .cpp&#34; 。如果您的意思是将timer.c
重命名为timer.cpp
- 请勿这样做! C和C ++是不同的语言。您应将其保留为timer.c
。您的编译设置应包括C和C ++编译器。 C编译器编译C代码,C ++编译器编译C ++代码,extern "C"
指令指示如何将两者粘合在一起。