在C或C++源文件中定义静态数组

13

我知道这是每个程序员都应该知道的问题,但我不知道。很久没有进行C编程了,已经忘记了很多东西。

我的问题是:

在头文件中定义了三个巨大的静态数组。有人告诉我,在头文件中将它们声明为extern,并在单个C或C++源文件中定义它们会更好。

我该如何做到这一点?

这是我的头文件:

#ifndef _TEMPLE_OBJECT_H_
#define _TEMPLE_OBJECT_H_


#define NUM_TEMPLE_OBJECT_VERTEX 10818

static const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};
static const float TEMPLENormals[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};
static const float TEMPLETexCoords[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};

#endif

如果我使用C++源文件,我是否需要定义一个类?

更新:
我认为问题是:
包含这些头文件的每个源文件(甚至是间接包含的)都将生成自己的定义,这些静态数组的定义。没有保证编译器/链接器将它们优化成单个定义,即使在未使用它们的源文件中也是如此。事实上,在许多情况下,编译器无法将它们优化掉。这可能会导致您的静态数据消耗大量磁盘空间,并可能消耗运行时内存。

谢谢。


GCC和启用优化构建不应该是这种情况。以下是关于"-fkeep-static-consts"的信息,来源于[https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html]https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html 即使变量没有被引用,在未开启优化时也会发出声明为static const的变量。 GCC默认启用此选项。如果您想强制编译器检查变量是否被引用,无论是否开启了优化,请使用-fno-keep-static-consts选项。 - Andy
5个回答

21

staticextern同时使用没有意义。static在文件范围内使数组对其他文件不可访问,而extern告诉编译器你的数组在其他地方定义。

你可以像321008建议的那样做,除了你不声明你的数组为静态的,这是非法的C和C++。这给你三个全局变量,你可以在包含头文件的任何地方使用它们。

例如像这样:

// .h file:

extern const float TEMPLEVertices[];

// .cpp (or .c) file:

const float TEMPLEVertices[] = { 1.0, 2.0, 5.6 /* or whatever*/ };

或者你可以像Fortran建议的那样做,但这只会给你文件范围内的访问权限,而不是全局变量。

如果你使用C++源文件,你不需要以任何方式定义一个类。与Java不同,C++不会强制你进入面向对象的设计(无论好坏如何,这可能是可以讨论的,但无论如何)。

编辑:至于你的问题更新,那是因为你将它们定义为static。如果你只想要全局变量,你不应该这样做,而是保持一个单一的定义(const float),并使用extern引用它,就像我上面的例子一样。


编译通过,但链接器报错:undefined reference to TEMPLEVertices'`,其他两个数组也是同样的情况。 - VansFannel
+1 表示“您不必以任何方式在 C++ 源文件中定义类”。 - BeeBand
@VansFannel:你的代码是什么?你可以更新一下你的问题吗?请注意,无论何时你想使用数组,都必须包含.h文件。 - user1481860
@VansFannel:那你复制错误了。所提供的代码必须能够编译和链接。 - jweyrich
@jweyrich:你说得对。我忘记将新的C源文件添加到makefile中了。抱歉。 - VansFannel
如果我想在 h 文件中定义内容怎么办? - Royi

7
您的头文件变成了:
#ifndef _TEMPLE_OBJECT_H_
#define _TEMPLE_OBJECT_H_


#define NUM_TEMPLE_OBJECT_VERTEX 10818

extern const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3];
extern const float TEMPLENormals[NUM_TEMPLE_OBJECT_VERTEX * 3];
extern const float TEMPLETexCoords[NUM_TEMPLE_OBJECT_VERTEX * 3];

#endif

当你的源文件变成以下内容:
// include header
const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};
const float TEMPLENormals[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};
const float TEMPLETexCoords[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...};

// rest of the source

更新:如果您正在显式指定数组,则不必提及其大小。也就是说,您可以这样做:
const float TEMPLEVertices[] = {...};

或者

const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3];

这就是你要做的!@ Øystein:你认为它有什么问题? - edgar.holleis
@341008:在静态变量中不能使用 extern,否则会导致链接错误。 - jweyrich
дҪ дёәд»Җд№ҲиҰҒдҪҝз”Ё extern const float *TEMPLEVertices иҖҢдёҚжҳҜ extern const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3]пјҹ - VansFannel
@VansFannel: 你在尝试我的代码吗?如果是的话,请评论我的答案并告诉我哪里有问题 :) 如果你在尝试上面那个答案的代码,那么这是不合法的,并且应该运行失败。 - user1481860
2
抱歉各位。我被叫走了一会儿,回来后发现有这么多人在努力修改这段代码片段。你们都是对的。static关键字应该去掉(因为复制粘贴的原因)。在头文件和源文件中使用[]/[n]时要保持一致,而不是混用[]/*(这是我的问题)。对于造成的困惑,我感到非常抱歉。更新了代码。 - 341008

6
我曾在Quake2源代码中看到一个有趣的“技巧”,实际上只是一种不寻常的使用include的方式:
只需执行:
static const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3] = {
#include "TEMPLEVertices.txt"
};

等等只保留所包含文件中的数据。

您仍然可以在编译单元中声明它们为extern,但这样可以使事情变得更加整洁。

等等只保留所包含文件中的数据。

您仍然可以在编译单元中声明它们为extern,但这样可以使事情变得更加整洁。


谢谢您的回答,但我认为我会遇到同样的问题。我已经更新了我的问题,并提供了更多关于这个问题的细节。 - VansFannel

4

其实很简单,我将用一个更简单的例子来进行演示,一个简单的原始常量。

在您的项目中,有两个文件pi.hpi.cpp

pi.h的内容如下:

#ifndef _PI_H
#define _PI_H

extern const double PI;

#endif

pi.cpp文件的内容如下:

#include "pi.h"

const double PI = 3.1415926535;

如果您想使用这个常量,只需在需要的地方包含pi.h即可。该值将始终从相同位置读取。
几乎任何东西都可以这样做 - 数组,对象,对象数组,STL容器等。只需确保不过度使用此技术 - 特别是当声明为extern的对象不是const时,您可能会创建一些难以跟踪的副作用。但对于常量数据,这就是您所做的。

0


我通常使用一个简单的技巧。

a) 在每个C/CPP文件中,我定义文件名_C
b) 在每个H/HPP文件中,我定义文件名_H

然后...

这将是你的包含文件

#ifndef _TEMPLE_OBJECT_H_
#define _TEMPLE_OBJECT_H_

#define NUM_TEMPLE_OBJECT_VERTEX 10818

#ifdef _TEMPLE_OBJECT_C
const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3] = {...} ; /* Put here your const values */
#else
extern const float TEMPLEVerticies[] ;
#endif

#endif

如果我没错的话,这应该可以工作(或者非常类似于那个)... :o)


我想在C或C++源文件中放置数组定义。 - VansFannel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接