首页 > 解决方案 > 奇怪的静态函数行为

问题描述

我正在查看静态函数,我知道它们的范围仅限于声明它们的文件。为了澄清,我使用带有 GCC 的代码块。如果我在 a 中声明函数.c 文件并将其包含在我的 main.c 文件中,可以访问该函数(但如果定义了非静态函数,编译器会报错,因为我有多个定义)。但是,如果我有一个带有一些静态函数和另一个非静态函数的 ac 文件,那么静态函数是不可访问的并且非静态函数是可访问的。这对我来说是一个相当奇怪的。我知道#include 指令将要包含的文件的内容复制到声明包含指令的文件中。但是为什么我可以访问非静态函数而不在 main.c 文件中包含 .c 文件呢?关于我可以在哪里阅读该主题的任何建议?我认为它与链接有关,但我可能错了。

标签: cfunctionstatic

解决方案


当一个函数被声明为没有static时,它具有外部链接1这意味着,当程序链接2时,可以使不同翻译单元3中的相同名称指代相同的事物。

例如,当您在一个源文件中定义函数时int square(int x) { return x*x; },编译该源文件会生成一个目标文件,其中包含“函数foo在此处定义”的信息。当您在另一个源文件中声明一个函数并使用该函数时,例如int square(int x); … b = square(a);,编译该源文件会生成一个目标文件,其中包含“该函数foo在此处使用”的信息。当链接器或程序加载器处理这些目标文件时,它会修改foo用于引用foo定义的位置的位置。

如果您使用一个函数而不在该翻译单元中声明它,您的编译器可能会为该函数提供一个默认声明,就好像它已被声明为返回int而没有关于其参数的信息。这种行为是旧版本 C 的遗留问题。很可能您的编译器会为此发出警告,例如“函数的隐式声明”。您不应忽略此警告。当它出现时,找到导致警告的代码并修复它——或者更正拼写错误的函数名的键入,或者插入函数的声明。

使用 GCC 或 Clang 时,您应该使用开关-Werror将警告提升为错误,以便编译器不会编译导致警告消息的程序。虽然这起初可能会使编译程序变得更加麻烦,但它会使您尽早修复错误并学习正确编程。

脚注

1使用static, 函数的标识符具有内部链接。对象标识符的规则(你可能认为是变量)更复杂,它们也可以没有链接

2实际上,每次编译都会产生一个目标模块。链接将目标模块组合成一个可执行程序,或者在复杂的构建中,新的目标模块。

3翻译单元是正在编译的源文件,包括它与#include语句一起包含的所有文件。


推荐阅读