【问题标题】:How to create a header file in a large C code base?如何在大型 C 代码库中创建头文件?
【发布时间】:2013-11-21 06:01:28
【问题描述】:

我知道如何编写 .h 文件并包含守卫。我想编写一个包含全局变量的新 bar123.h 文件。假设 bar123.c 不存在。

其他头文件,例如bar.h 将包含 bar123.h,以使全局变量在需要它们的地方可见。

一个问题是,如果 foo.c 包含 foo.h,而 foo.h 又包含 bar.h,而 bar.h 又包含 bar123.h,那么 foo.c 是否总是 包含 bar123.h?

另一个问题是,我应该如何修改 Makefile 和 Kbuild 文件?

我正在寻找一个简单的 hackish 解决方案。

【问题讨论】:

  • 您可能已经意识到这一点,但以防万一:请记住,C #include preprosessor 指令只是将包含文件中的文本放入编译。没有花哨的“导入”语义,您只需将头文件复制粘贴到编辑器中的源代码中即可(我只知道一个例外,非标准 #pragma once )。
  • 谢谢海德。我实际上还没有制作新的标题。现在只需粘贴'extern int baz;'分成多个头文件。编译良好,但在运行时我仍然收到“未知符号 baz”。 ('umac: Unknown symbol baz (err 0)' on the openwrt router serial terminal Tera Term if that help.)
  • 我为您的评论写了一个答案,但您可能想更新问题... :)
  • 谢谢海德。解决方案似乎并不容易。下次我可以试试。目前正在通过另一种方法。

标签: c include global-variables header-files kbuild


【解决方案1】:

回答您的第一个问题 - 是的 foo.c 将始终包含 bar123.h。

第二个查询,在 Make 文件中,您需要添加的唯一更改是将这个 bar123.h 添加到头包含文件的列表中。由于您没有生成任何新的 .o 文件,因此您无需更改该部分。

希望它能回答你的问题

【讨论】:

  • 感谢 Srikanth,非常直截了当。你能给出一个链接说 foo.c 将始终包含 bar123.h 吗?这种现象叫什么?
  • 它是递归包含头文件的,我刚刚引用了我的经验。如果您想进一步参考,可以转到链接stackoverflow.com/questions/705676/…
【解决方案2】:

全局变量必须存在于某处,并且只能存在于一个地方。这意味着它只需要在一个地方声明。

记住:H 文件只是告诉编译器事物存在于某处。 C 文件提供了这些东西的实际定义。

假设您的全局不属于其他任何地方,我们将添加一个globals.c

#include "globals.h"
int g_myGlobal;

应该有对应的globals.h:

#ifndef _GLOBALS_H
#define _GLOBALS_H

extern int g_myGlobal;

#endif // _GLOBALS_H

在没有extern.h 文件中声明全局变量几乎肯定是错误的。如果您这样做,编译器将尝试在包含该标头的每个 C 文件 中声明该变量,这将导致链接时出现“多重定义”错误。 (我假设这就是你问“foo.c 总是包含 bar123.h?”的原因,并解释了为什么它不重要。)

main.h:

#include "globals.h"
int main() {
    g_myGlobal = 42;
}

【讨论】:

    【解决方案3】:

    它的短处是这个。您不能在头文件中包含全局,然后将该头包含在其他地方。你会得到讨厌的“重新定义”错误。除非……

    这就是我的工作。

    头文件happy.h

    extern int happy; // Global variable
    

    主文件

    #include "happy.h"
    
    int happy = 12;
    

    其他文件.c

    #include "happy.h"
    
    int happy = 10;
    

    关于问题 2:这取决于编译器。有些人会隐式添加它,但是,好的编码将是包含您打算从中使用函数的任何 .h 文件的编码。

    注意* 将全局变量放在标题中绝不是一个好主意。标头的预期用途是结构定义和“公共”函数声明。结构/联合等定义仅在必要时包含在标头中。示例:

    typedef struct
    {
        int happy;
        char sad;
    } my_mood_t;
    
    my_mood_t *what_is_my_mood( int dog_ate_my_lunch );
    

    【讨论】:

    • 谢谢。 '有些会隐式添加 [bar123.h 到 foo.c]' 所以没有得到确认? gcc 编译器是否递归地包含所有头文件依赖项?我不确定我是否使用了正确的术语。
    • 我认为最后一行应该使用花括号而不是括号,因为它正在初始化结构。
    【解决方案4】:

    来自OP的评论:

    编译正常,但在运行期间我仍然收到“未知符号 baz” 运行。 ('umac: Unknown symbol baz (err 0)' 在 openwrt 路由器上 串行终端 Tera Term,如果有帮助的话。)

    如果应用程序链接正常,但由于该错误而无法运行,这意味着在构建时链接期间,具有该符号的动态库可用。但是,在运行时,该符号不可用。快速修复:

    • 确定哪个库有符号
    • 确保该库存在于您运行应用程序的位置,并记下它的路径
    • 不只是运行application,而是使用命令LD_LIBRARY_PATH=/path/to/the/library/directory application(您也可以使用该值单独导出LD_LIBRARY_PATH,但随后将为每个程序设置它,而不仅仅是那个)。

    这不是唯一的方法。您也可以将库复制到系统库目录并运行ldconfig 以更新系统库缓存。或者你可以使用rpath 机制。但在研究这些之前,请从 LD_LIBRARY_PATH 环境变量开始,让事情正常进行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-03
      • 1970-01-01
      • 2011-02-19
      • 2013-05-22
      相关资源
      最近更新 更多