3

介绍

我是一位经验丰富的程序员,在面向对象范式方面拥有多年经验。最近我决定尝试更熟悉和更熟悉比 C# 或 Java 等语言更低级别的语言,所以我正在深入研究C,并将尝试用它创建一些游戏。

一切进展顺利,现在我正试图通过将函数定义移动到单独的 .c 文件中来更好地组织我的代码。由于包含在C中的性质,这就是我开始感到不舒服的地方。我非常熟悉它的工作原理,以及编译期间的预处理阶段。问题是我仍然不确定我是否正确处理了这个问题。

我认为我的问题类似于这里提出的问题。虽然它并没有完全满足我需要知道的。

问题

本质上,我正在使用两个库创建一个 OpenGL 项目。一种是glew(用于 OpenGL 函数加载),另一种是GLFW(用于窗口处理和 OpenGL 上下文创建)。我有两个 .c 文件,一个名为main.c,另一个名为windowInitialize.c。问题是,main.cwindowInitialize.c都依赖于 glew 和 glfw 库。

在我的main.c文件中,我执行以下操作:

#include "includes/GLEW/glew.h"
#include "includes/GLFW/glfw3.h"
#include "windowInitialize.h"

此外,main.c执行以下相关函数调用:

if (!initializeGLFW())
 return -1;

GLFWwindow *window = createOpenGLWindow(3, 3, 640, 480, "Hello OpenGL");

/* It is important that we initialize glew AFTER initializing GLFW and setting up
the OpenGL context, as GLEW needs a current context to work */
initializeGLEW();

windowInitialize.c包含函数initializeGLFWinitializeGLEW以及createOpenGLWindow的定义。尽管main.c源代码仍然使用glewglfw来实现主循环,但它们都引用了函数等。

现在,windowInitialize.c包含以下内容:

#include "windowInitialize.h"
#include "includes/GLEW/glew.h"
#include "includes/GLFW/glfw3.h"
#include <stdio.h>

然后继续填写函数定义。所以这就是交易。如果 glew 和 glfw 库以及 stdio 实际上需要使用这两个文件(用于打印调试消息等)。

我觉得这不是正确的方法,但我不确定。我相信编译器/链接器不抱怨双重声明的原因是 main.c 和 windowInitialize.c 获取单独的目标代码文件。

我的问题是,链接器是否足够聪明,只将这些声明放在可执行文件中一次?所以即使我在几个地方包含这些标题,它不会对文件大小等产生任何影响?这甚至是处理多个源文件之间常见依赖关系的正确方法吗?还是我应该使用另一种方法?

4

2 回答 2

6

你所描述的一切似乎都是正常的做事方式。您的两个编译单元仅在这些标头中获得相同的函数前向声明,而不是来自库的实际重复定义。

我的问题是,链接器是否足够聪明,只将这些声明放在可执行文件中一次?

链接器当然不关心您包含哪些头文件 - 它是链接器,而不是编译器。

所以即使我在几个地方包含这些标题,它不会对文件大小等产生任何影响?

额外/未使用的函数前向声明对二进制大小没有影响。

这甚至是处理多个源文件之间常见依赖关系的正确方法吗?

是的,你似乎以完全正常的方式做事。

对于您的项目,您应该执行以下操作:

cc -c -o main.o main.c                           # compile main.c
cc -c -o windowInitialize.o windowInitialize.c   # compile windowInitialize.c
cc -o myProgram main.o windowInitialize.o -lglew -lglfw # link objects with necessary libraries to create executable

但是,实际上,使用 makefile 会更好:

myProgram: main.o windowInitialize.o
    cc -o $@ $^ -lglew -lglfw

使用它的例子:

$ make
cc    -c -o main.o main.c
cc    -c -o windowInitialize.o windowInitialize.c
cc -o myProgram main.o windowInitialize.o -lglew -lglfw
于 2013-07-31T21:53:29.033 回答
1

链接器将仅使用您实际使用的库中的那些函数,并且只使用一次。至于方法,在我正在阅读的书中 atm 建议是制作一个包含所有库、函数声明、定义的文件,并且只包含一个文件,例如。mydefinitions.h ,而不是在项目的每个文件中单独执行。希望能帮助到你。

于 2013-07-31T22:00:39.160 回答