.c文件中的静态函数/变量

.c文件中的静态函数/变量,c,linker,C,Linker,我遇到的大多数解释描述了为什么在全局函数或变量上使用static关键字,它们的效果如下:全局范围中的静态标记函数或变量对文件不可见更具体地说,是定义它们的外部编译单元。考虑到除了与inline结合使用外,.h文件中很少使用静态函数,我想问:为什么我们需要将.c文件中的函数和变量标记为静态,而此类.c文件从未包含在任何其他编译单元中,因此无法将函数标记为静态,从而使其在其他编译单元中不可见?请考虑: // a.c static void f(void) {...} void DoIt(void)

我遇到的大多数解释描述了为什么在全局函数或变量上使用static关键字,它们的效果如下:全局范围中的静态标记函数或变量对文件不可见更具体地说,是定义它们的外部编译单元。考虑到除了与inline结合使用外,.h文件中很少使用静态函数,我想问:为什么我们需要将.c文件中的函数和变量标记为静态,而此类.c文件从未包含在任何其他编译单元中,因此无法将函数标记为静态,从而使其在其他编译单元中不可见?

请考虑:

// a.c
static void f(void) {...}
void DoIt(void) {...}

现在,编译器从每个源文件生成对象文件,而不知道存在名称冲突。当a和b链接到程序中时,无效的fvoid签名对链接器隐藏,因为static关键字将它们限制在文件范围内,但它可以看到两个无效的DoItvoid签名,因为它们都在全局范围内。现在考虑:

// c.c

extern void DoIt(void);

static void f(void)
{
    DoIt(void); // Which implementation should be called here?
}
仅仅因为您从未编写过包含函数名的头文件,并不意味着您或某些程序员不会尝试在其他地方使用该符号名。使用static可以限制全局范围内的名称污染,因此希望不会遇到太多冲突

我们在文件范围中隐藏符号名的另一个原因是,使其他程序员难以使用我们不希望他们使用的函数。您在全局范围内公开的每个符号都是一个潜在的支持调用。如果有数百个产品/开发人员依赖于您的内部位,那么重构或修改代码会变得非常困难。通过在文件范围内对他们隐藏这些符号,你是在说我不支持你依赖这些符号,因此如果他们继续这样做,当你删除它们或修改代码使用它们的方式时,他们无权抱怨。

考虑:

// a.c
static void f(void) {...}
void DoIt(void) {...}

现在,编译器从每个源文件生成对象文件,而不知道存在名称冲突。当a和b链接到程序中时,无效的fvoid签名对链接器隐藏,因为static关键字将它们限制在文件范围内,但它可以看到两个无效的DoItvoid签名,因为它们都在全局范围内。现在考虑:

// c.c

extern void DoIt(void);

static void f(void)
{
    DoIt(void); // Which implementation should be called here?
}
仅仅因为您从未编写过包含函数名的头文件,并不意味着您或某些程序员不会尝试在其他地方使用该符号名。使用static可以限制全局范围内的名称污染,因此希望不会遇到太多冲突


我们在文件范围中隐藏符号名的另一个原因是,使其他程序员难以使用我们不希望他们使用的函数。您在全局范围内公开的每个符号都是一个潜在的支持调用。如果有数百个产品/开发人员依赖于您的内部位,那么重构或修改代码会变得非常困难。通过在文件范围内对他们隐藏这些符号,你是在说我不支持你依赖这些符号,所以如果他们继续这样做,当你删除它们或修改代码使用它们的方式时,他们没有权利抱怨。

一般来说,你不应该包含.c文件。如果将函数或变量标记为静态,则链接器无法从其他编译单元引用它。这可能无法回答您的问题,但您的问题有点不清楚。我的意思是您只是澄清了它,作为一般规则,您不应该包含.c文件。这就是我的意思,如果你没有在任何地方包含.c文件,那么为什么你需要将全局变量和函数标记为static呢?我以为你这样做是为了防止它们在其他编译单元中使用[你说的其他不应该包含在彼此中的.c文件].由于函数/变量未导出,因此很难了解它们。这也使得从其他翻译单位打电话给他们变得不可能。它还允许其他转换单元创建自己的静态函数或具有相同名称的变量,这些函数或变量对实用程序类型的函数很有用。如果将函数或变量标记为静态,则链接器无法从其他编译单元引用它。这可能无法回答您的问题,但您的问题有点不清楚。我的意思是您只是澄清了它,作为一般规则,您不应该包含.c文件。这就是我的意思,如果你没有在任何地方包含.c文件,那么为什么你需要将全局变量和函数标记为static呢?我以为你这样做是为了防止它们在其他编译单元中使用[你说的其他不应该包含在彼此中的.c文件].由于函数/变量未导出,因此很难了解它们。它也使它变得很小
可能从其他翻译单位打电话给他们。它允许其他翻译单元创建自己的静态函数或具有相同名称的变量,这些函数或变量对实用程序类型的函数很有用,以下内容:使用static标记定义是否使链接器不会尝试将标记为static的定义分配给程序上其他具有相同名称的兼容声明?是。如果它是静态的,编译器将对链接器隐藏它,因此它不容易使用。对于大多数系统上的大多数工具链,这意味着符号将不在公共符号表中。一些工具链确实允许链接器配置文件,这些文件允许您定义模块或内存中任意地址内的外部符号声明和特定偏移之间的映射。虽然并非出于此目的,但它可以用于访问您的私有实现,这违反了您的意图。它通常在没有运行时加载程序的系统上使用。作为澄清,我想问以下问题:将定义标记为static是否会使链接器不会尝试将标记为static的定义分配给程序上其他具有相同名称的兼容声明?是的。如果它是静态的,编译器将对链接器隐藏它,因此它不容易使用。对于大多数系统上的大多数工具链,这意味着符号将不在公共符号表中。一些工具链确实允许链接器配置文件,这些文件允许您定义模块或内存中任意地址内的外部符号声明和特定偏移之间的映射。虽然并非出于此目的,但它可以用于访问您的私有实现,这违反了您的意图。它通常用于没有运行时加载程序的系统。