我知道这是每个程序员都应该知道的问题,但我不知道。很久没有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 ++源文件,我可能需要定义一个类吗?
更新:
我认为问题是:
包含这些头的每个源文件(甚至是间接的)将为这些静态数组生成自己的定义。无法保证编译器/链接器会将它们优化为单个定义,即使在未使用它们的源文件中也是如此。事实上,在许多情况下,编译器无法优化它们。这可能会导致静态数据消耗大量磁盘空间,并可能导致运行时内存。
谢谢。
答案 0 :(得分:18)
static
和extern
同时毫无意义。文件范围内的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
引用它,如上面的示例所示。
答案 1 :(得分:7)
我曾经在Quake2源代码中看到一个有趣的“技巧”,实际上这只是一种使用包含的不寻常方式:
只是这样做:
static const float TEMPLEVertices[NUM_TEMPLE_OBJECT_VERTEX * 3] = {
#include "TEMPLEVertices.txt"
};
等
并保留所包含文件中的数据。
你仍然可以在编译单元中将它们声明为extern
,但这会使事情变得更加整洁。
答案 2 :(得分:5)
您的标头文件变为:
#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];
答案 3 :(得分:5)
在您的项目中,您有两个文件pi.h
和pi.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
的对象不是{{1}时,你可能会创建一些非常难以跟踪的副作用。但是对于不断的数据,你就是这样做的。
答案 4 :(得分:0)
我通常使用一个简单的技巧。
a)在每个C / CPP文件中,我定义 filename _C
b)在每个H / HPP文件中,我定义 filename _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)