7

我想在单个静态 C 程序中包含一堆数据(例如,图像,还有其他数据,嵌入在可执行文件中,因为我在没有文件的嵌入式平台上工作)。

因此,我写了一个小 img2c 从我的数据文件创建 const 数据,创建一个带有静态 const 数组初始化器的文件以放入闪存(使用 C99 不错的功能)

我的问题是,我应该把它们放在一个 .h 文件中,就像我见过很多次一样 - 例如 gimp 可以保存为 .h 文件,而不是 .c 文件 - 或者放在一个 .c 文件中,在标头中仅引用const extern 声明以供进一步引用,而不必包含所有数据并将其全部传递给编译器,并在每次使用时重新声明它?

预处理器宏是不可能的,因为我会引用它们的地址,而不是每次都包含整个数据。

4

4 回答 4

4

如果您将数据放入标头中,则每个拉入该标头的编译单元都将获得自己的数据副本。想象一下两个 .c 文件,每个文件都转到一个 .o。每个 .o 都会有一个数据副本,并且您的最终可执行文件可能比它需要的更大。

如果你把它放在一个 .c 中并在一个头文件中 extern 它,只有一个 .o 将包含数据,你的最终可执行文件可以更小。此外,如果您更改内容,如果只是更改单个 .c 而不是包含您的标头的所有 .c 文件,则重新编译会更快。

正如您所指出的,您也可能会遇到链接器问题,因为符号将被多次定义,请参阅Repeated Multiple Definition Errors 的答案,包括在多个 cpps 中包含相同的标头。将 extern 放在标头中并将数据放在 .c 中会更好

于 2012-08-09T13:09:18.490 回答
3

C 中的头文件没有什么特别之处。.h扩展不会改变编译器处理它们的方式。这更像是对人类的暗示“这个文件可能不包含任何代码”。

因此,如果您将实际的二进制数据放入其中,编译器将在包含标头的每个文件中创建数组的副本(而不是简单地添加对共享全局数组的引用)。

GIMP 会创建一个头文件,因为它不知道您打算如何使用这些数据。这个想法是,您将在一个文件中只包含这个头文件一次.c,然后以某种方式处理数据。如果它编写了一个.c文件并且您对代码进行了更改,那么当您要求 GIMP 更新数据时,它必须合并这些更改——这会很混乱。

于 2012-08-09T13:11:49.597 回答
2

与 C 中的所有内容一样,这里对于最佳实践存在一些争论。常见的做法是将实际值放在您的实现 (.c) 中,将声明 ( extern something something) 放在头文件 (.h) 中。这样,您可以更新这些值,而无需重新编译包含标头的每个文件。

答案几乎从不“每次使用时都重新声明”。

于 2012-08-09T13:09:26.553 回答
2

这可以通过确保仅在单个源文件中定义变量来完成。为此,需要一点预处理器“编程”。

头文件:

/* Standard include guard */
#ifndef X_H
#define X_H

#ifdef X_SOURCE
uint8_t data[] = { /* ... */ };
#else
extern uint8_t data[];
#endif

#endif  /* End of include guard */

源文件:

#define X_SOURCE
#include "x.h"

/* ... */

所有其他源文件只需要包含该文件"x.h",它们就可以引用data.

于 2012-08-09T13:10:59.350 回答