如何在C语言中的程序访问头文件中声明函数

时间:2014-08-04 12:49:10

标签: c header-files

同一目录中有三个文件 - mainfile.c,helper.c helper.h。。 helper.h包含foo1foo2的函数原型,struct声明和一些typedefs

header.h包含在helper.cmainfile.c中(helper.h也包含警卫,因此双重声明不是问题。)。函数foo1foo2helper.c

中定义

如果我在helper.h个文件中加入.c,我的理解是helper.h的内容在运行时.c文件中逐字逐句地粘贴({1}}时间。我的理解是否正确?

我曾经认为,如果我在foo1中调用mainfile.c,则控件会转移到foo1的开头,并且foo1无法与其他任何已定义的内容进行交互在helper.c。但是这种思路存在一些问题,因为当我在helper.c中声明一个全局变量时,两个函数都能够访问它。那么mainfile.c调用foo1foo2时会发生什么?

我对静态存储类的理解是它将局部变量转换为全局变量,因为所有函数都能够访问它。因此,如果我在 foo1 中声明一个静态数组,然后在foo2中调用mainfile.c,那么foo2是否能够访问此静态数组?

dictionary.c的内容应该是这样的

void foo1 (void)
{
    static int array[10] = {1,2,3,4,5,6,7,8,9,10}
    //more code 
}

void foo2 (void)
{
    array[7] = 4;
    // more code
}

当从mainfile调用foo2时,它是否能够访问静态数组。

3 个答案:

答案 0 :(得分:3)

mainfile.chelper.c都是单独的翻译单元,可以生成单个目标文件(受链接器限制)。一个ilustration你可以编译它们分别生成.o文件(或Windows平台上的.obj):

gcc -c helper.c
gcc -c mainfile.c

然后检查他们的符号,例如通过nm命令。要链接它们,请使用以下内容:

gcc helper.o mainfile.o

foo1调用mainfile.c时,该函数可以访问自己的"全局变量" (在helper.c中定义)并且如果该变量具有内部或外部链接并不重要(请注意,局部变量没有链接)。真实的是mainfile.c也可能(直接)访问它(即,在foo1函数旁边)只有当这样的变量具有外部链接时(它在任何函数之外定义)没有static存储类)。这也需要适当的声明,可取的方法是使用helper.h存储类在extern中声明它,而不使用inializer,例如:

extern int global_variable;

请注意,这会检查声明againt定义(因为您在"helper.h"源文件中包含helper.c标头)。

更新

正如@jweyrich指出的那样,有可能绕过"绕过"全局变量的内部联系,因此它可以(及其地址)提供给消费者"文件来源。这是一个简短的例子:

b.h

int *get_secret(void);

b.c

#include "b.h"

static int secret = 999;

int *get_secret(void) {
    return &secret;
}

a.c

#include <stdio.h>
#include "b.h"

int main(void)
{
    int *a;

    a = get_secret();
    printf("%d\n", *a);

    return 0;
}

即使secret全局变量具有内部链接(因为它具有static存储类),也可以在a.c中访问它。当某些函数返回用static声明的函数的指针时,相同的技术适用于函数。

答案 1 :(得分:2)

  

如果我在任何.c文件中包含helper.h,我的理解是helper.h的内容在运行时在.c文件中逐字地粘贴(逐字逐句)。我的理解是否正确?

部分正确。它是在编译期间,而不是在运行时。

  

我曾经认为,如果我在mainfile.c中调用foo1,控件将转移到foo1的开头,并且foo1不能与helper.c中定义的任何其他内容交互。但是这种思路存在一些问题,因为当我在helper.c中声明一个全局变量时,两个函数都能够访问它。

是的,这是错的。 编译单元可以引用其他编译单元中的符号,前提是符号被导出,例如:非静态函数,非静态全局变量等。

即使未通过标题(helper.h)公开非静态变量,也可以通过在编译单元中使用extern声明它来获得可见性。

  

那么当mainfile.c调用foo1或foo2时会发生什么?

没什么特别的。唯一的区别是foo1foo2(在helper.c中实现)可以从他们自己的编译单元中看到具有静态存储的所有函数和全局变量。

  

我对静态存储类的理解是它将局部变量转换为全局变量,因为所有函数都能够访问它。因此,如果我在foo1中声明一个静态数组然后在mainfile.c中调用foo2,那么foo2能够访问这个静态数组吗?

如果该静态数组是全局的,那么来自同一编译单元的所有函数都可以访问它,无论是谁调用它们。

<强>更新

  

因此,如果我在foo1中声明一个静态数组,然后在mainfile.c中调用foo2,那么foo2能够访问这个静态数组吗?

不。您尝试引用的数组在foo1范围内声明,其范围foo2无法访问。

答案 2 :(得分:1)

你所缺少的关键是所谓的&#34;编译单元范围&#34;。每个.c文件都是单独编译的。结果是一个目标文件,它公开了在全局范围内定义的所有符号。

编译后链接。链接器收集所有编译单元并将它们全部抛出到一个大存储桶中。从那里,它在程序使用的所有编译单元的所有符号之间建立连接(这也意味着库)。

  

我对静态存储类的理解是它将局部变量转换为全局变量

实际上恰恰相反。声明为static的全局范围变量不会被编译单元公开,因此链接器不会将其用于程序范围的符号解析。