【问题标题】:C++ Header File and Linker Errors [closed]C++ 头文件和链接器错误 [关闭]
【发布时间】:2012-11-04 08:05:46
【问题描述】:

我在编译代码时遇到了奇怪的错误。我猜头文件没有被正确链接,因为那些出错的变量中的每一个都已在我正确#include的'variables.h'中指定。奇怪的是,如果我在 main.cpp 中注释掉使用变量的区域,则会在另一个文件 readfile.cpp 中弹出相同变量的其他一系列错误。下面是错误输出,以及我的 main.cpp 和 variables.h 代码。有什么想法吗?

g++ -c main.cpp 
g++ -c readfile.cpp 
g++ -c Objects.cpp 
g++ -o raytracer main.o readfile.o Objects.o
Undefined symbols for architecture x86_64:
  "_depth", referenced from:
      init()    in main.o
      readFile(char const*)in readfile.o
  "_diffuse", referenced from:
      readFile(char const*)in readfile.o
  "_emission", referenced from:
      readFile(char const*)in readfile.o
  "_filename", referenced from:
      init()    in main.o
  "_fov", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_height", referenced from:
      init()    in main.o
      readFile(char const*)in readfile.o
  "_lookatx", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_lookaty", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_lookatz", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_lookfromx", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_lookfromy", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_lookfromz", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_maxvertnorms", referenced from:
      init()    in main.o
      readFile(char const*)in readfile.o
  "_maxverts", referenced from:
      init()    in main.o
      readFile(char const*)in readfile.o
  "_shininess", referenced from:
      readFile(char const*)in readfile.o
  "_specular", referenced from:
      readFile(char const*)in readfile.o
  "_spherecount", referenced from:
      init()    in main.o
  "_spheres", referenced from:
      readFile(char const*)in readfile.o
  "_triangles", referenced from:
      readFile(char const*)in readfile.o
  "_tricount", referenced from:
      init()    in main.o
  "_trinormals", referenced from:
      readFile(char const*)in readfile.o
  "_trinormcount", referenced from:
      init()    in main.o
  "_upx", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_upy", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_upz", referenced from:
      init()    in main.o
      initCamera(float*)in readfile.o
  "_vertexcount", referenced from:
      init()    in main.o
  "_vertexnormcount", referenced from:
      init()    in main.o
  "_vertices", referenced from:
      readFile(char const*)in readfile.o
  "_vertnormals", referenced from:
      readFile(char const*)in readfile.o
  "_width", referenced from:
      init()    in main.o
      readFile(char const*)in readfile.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

下面是变量.h..

#include "vertexnormal.h"
#include "sphere.h"
#include "tri.h"
#include "trinormal.h"
#include "vec.h"

#include <string>
#include <vector>

using namespace std;

// width and height specify image size
extern float width;
extern float height;

// maximum depth for a ray (level of recursion)
extern int depth;

// the output file to which the image should be written
extern string filename;

// camera specifiations (should i put in a struct?)
extern float lookfromx;
extern float lookfromy;
extern float lookfromz;
extern float lookatx;
extern float lookaty;
extern float lookatz;
extern float upx;
extern float upy;
extern float upz;
extern float fov;

//***************************//
//  Geometry Specifications  //
//***************************//

// specifies the number of vertrices for tri specifications
extern int maxverts;

// specifies the number of vertices with normals for tri specifications
extern int maxvertnorms;

// pile of inputted vertices
// might need to #include glm file                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
extern vector<vec> vertices;

// pile of inputted vertices with specified normals
extern vector<vertexNormal> vertnormals;

// pile of inputted spheres
extern vector<sphere> spheres;

// pile of inputted triangles
extern vector<tri> triangles;

// pile of inputted triangles using vertices with specified normals 
extern vector<triNormal> trinormals;

extern int vertexcount;
extern int vertexnormcount;
extern int spherecount;
extern int tricount;
extern int trinormcount;

//**************************//
//  Materials Specifiations //
//**************************//

extern float diffuse[3];
extern float specular[3];
extern float shininess;
extern float emission[3];

这是我的 main.cpp,

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

#include "Objects.h"

using namespace std;

#include "readfile.h"
#include "variables.h"


void init() {
    cout << "Reading in scene file... \n";
    cout << "Image size has been set to a " << width << " x " << height << " output. /n";
    cout << "The maximum recursion depth has been set to " << depth << ". \n";
    cout << "The image will be output to " << filename << ".png. \n";

    cout << "The camera has been instantiated with the following properties: \n";
    cout << "\t POSITION: (" << lookfromx << ", " << lookfromy << ", " << lookfromz << ") \n";
    cout << "\t DIRECTION: (" << lookatx << ", " << lookaty << ", " << lookatz << ") \n";
    cout << "\t UP: (" << upx << ", " << upy << ", " << upz << ") \n";
    cout << "\t FIELD OF VIEW: " << fov << " \n";

    cout << "An amount of " << vertexcount << " vertices has been specified with a maximum of " << maxverts << " allowed. \n";
    cout << "An amount of " << vertexnormcount << " vertices with normals has been specified with a maximum of " << maxvertnorms << " allowed. \n"; 

    cout << "An amount of " << spherecount << " spheres have been specified. \n";
    cout << "An amount of " << tricount << " triangles have been specified. \n";
    cout << "An amount of " << trinormcount << " triangles with calculated vertex normals have been specified. \n";
}


int main (int argc, char * argv[]) {
    readFile(argv[1]);
    init();
    return 0;
}

【问题讨论】:

  • 您能否将代码缩减为一个表现相同行为的较小示例?超过 90% 的问题与实际问题无关。通过消除代码,您甚至可以自己发现问题。
  • 这是一个真正惊人的全局变量数量。在您了解了如何正确使用全局变量之后,接下来您应该学习的是如何构建您的代码,这样您就不需要使用它们了。你真的不会用这种编码风格走得太远。也许阅读了面向对象,C++ 语言就是为此而发明的。甚至只是阅读函数参数返回值
  • @john 是的,我知道这是相当多的全局变量,但是许多图形应用程序作为状态机运行,因此存在需要跟踪的变量数量膨胀的趋势。大约四分之一的变量用于调试目的,我同意的唯一变量可以更好地实现是相机规格参数。我这样做是因为我只是想尽快启动和运行文本解析器。无论如何,再次感谢所有的帮助和建议。现在可以使用了。

标签: c++ compiler-errors g++


【解决方案1】:

试试这个:

  1. 打开您的 variables.h 头文件。
  2. 复制所有extern 变量声明。
  3. 打开您的 main.cpp 文件。
  4. 粘贴从 (2) 复制的所有声明。
  5. 在同一 main.cpp 中删除关键字 extern 从每个声明中。
  6. 保存所有文件。
  7. 查看extern 的工作原理。有件事告诉我你在学习中错过了这一点。

好的,这已经在 SO what 中介绍了几千次,但对于 OP:

声明变量的存在

// DECLARE myvar, an int variable. no storage has been set aside
//  this is simply telling the compiler this thing exists.. somewhere.
extern int myvar;

定义变量的存在性

// DEFINE myvar, an int variable. storage *is* set aside here.
//  only ONE of these, by this name, can be in your global 
//  namespace in your program.
int myvar = 0;

传统上,extern 声明位于标头中,但定义始终位于 c/cpp 文件中。对于您的程序中使用的任何extern 声明的变量,必须有一个匹配的定义。

这如何适合您的情况 您的所有变量都在variables.h声明,但无论如何都没有定义。通过告诉您将所有这些声明复制/粘贴到源文件中(任何都可以;我选择 main.cpp 因为它已经在您的项目中),然后删除 extern 关键字在那个源文件(不是标题)中,你基本上是在定义它们都正式存在的地方。现在,在您的其他源文件中对extern'ed 变量的所有引用终于可以在链接时挂钩。

侧边栏 在您的变量被定义的 c/cpp 文件中,确保将它们初始化为正确的值。这是您唯一可以做到的地方。您不能在任何 extern 声明中执行此操作。它只能在定义上完成。

头文件

extern int myvar; // note: no initial value.

源文件

int myvar = 0; // note: initialized to zero (0)

希望这至少有点道理。

【讨论】:

  • 感谢 WhozCraig 的回复。如果可能的话,我想让它们远离我的 main.cpp。如果我从 'variables.h' 中删除了 extern 关键字,是否有解决办法?
  • '如果可能,我希望将它们排除在 main.cpp 之外'。他们必须去某个地方,如果不是 main.cpp 然后是另一个 .cpp 文件。甚至可以创建一个名为 globals.cpp 的 .cpp 文件。并且不只是删除 extern 是行不通的。但当然,真正的答案是根本不使用全局变量。也许您可以将其用作学习经验,尝试重写您的代码,这样您就不需要全局变量。正如您的评论所说,将它们放入结构中将是一个开始。那么你需要学习的就是如何将变量从一个函数传递到另一个函数。
  • @KevinPamplona:不,这会导致多个定义。请记住,#include 字面意思 仅包含文件的内容 - 每次您 #include 定义一个新定义时。将extern 保留在标题中,然后将定义(不带extern)添加到相关的.cpp 文件中。或者更好的是:根本不要使用全局变量。
  • 是的,约翰说的。如果没有别的,则创建一个 variables.cpp 文件并将它们全部放入其中,但是 将 extern 限定符放在 variables.h 中所有的前面并且在你发誓时必须把所有这些 @987654339 @decls 回到 variables.h 中,将其视为没有那么多全局变量 =)的动机
【解决方案2】:
extern float lookfromx;
extern float lookfromy;
extern float lookfromz;
extern float lookatx;
extern float lookaty;
extern float lookatz;

这些只是声明。您需要在程序的某处定义这些变量(例如,在 variables.cpp 中)。要进行这些定义,您可以

  • 去掉extern关键字

  • 添加一个初始化器(= value;)

【讨论】:

  • 谢谢阿门。它奏效了,有点。现在我得到了重复的错误,例如'duplicate symbol _lookfromx in: main.o readfile.o duplicate symbol _lookfromy in: main.o readfile.o' --- 为了解决这个问题,我尝试删除 #include "variables.h"来自 readfile.cpp,但随后出现“未声明”错误。如何解决重复问题?
  • @KevinPamplona:您必须将声明保留在 .h 文件中,并将定义保留在 .cpp 文件中。
【解决方案3】:

您的 variable.h 文件只是让您的变量在全局范围内的其他文件中可移植,但仍需要声明它们。确保在主文件中声明实际变量(初始化的常规方法)。

extern 关键字声明一个变量或函数,并指定它具有外部链接(其名称在定义它的文件之外的文件中可见)。修改变量时,extern 指定变量具有静态持续时间(在程序开始时分配,在程序结束时释放)。变量或函数可以在另一个源文件中定义,或者稍后在同一文件中定义。默认情况下,文件范围内的变量和函数声明是外部的。

Read more on the extern keyword

【讨论】:

  • 感谢 Need4Sleep。我按照 Armen 的建议删除了 extern 关键字,但现在出现重复符号错误。在 readfile.cpp 中删除 #include "variables.h" 不起作用。有什么想法吗?
  • 确保您的 variables.h 文件没有被多次包含,这可能是您的副本的问题。添加您通常会在类头文件中看到的标头保护
  • 'variables.h' 仅在 readfile 和 main 中声明一次,但我没有任何标题保护——这可能是问题吗?
  • 添加它们不会有什么坏处,试一试。应该不会超过一分钟
  • 嗯,我将 variables.h 封装在标头保护中,但重复错误仍然存​​在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
  • 1970-01-01
相关资源
最近更新 更多