【问题标题】:weird static function behaviour奇怪的静态函数行为
【发布时间】:2021-09-24 21:37:23
【问题描述】:

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

【问题讨论】:

  • 发布演示问题的代码将使问题和潜在答案更加清晰。
  • 你不应该 #include 一个 .c 文件,所以这没有实际意义
  • 代码值一千字。
  • 我猜问题会变成“为什么我可以在另一个单元中调用未声明的函数”

标签: c function static


【解决方案1】:

当一个函数声明时没有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 语句的文件。

【讨论】:

    【解决方案2】:

    所以我在另一个 stackoverflow 问题中找到了对您问题的正确答案,但在开始之前,我想解释一下为什么包含 .c 文件是不好的做法,不应该这样做:

    1. 为什么不包含 .c 文件却可以访问非静态函数?
    • 如果您没有明确包含所述 .c 文件,这通常在 c 中是不可能的。如果我这样做,我会得到一个“隐式声明”函数,因为编译器无法识别这些函数,因为它们之前没有被声明过。
    1. relevant stack overflow answer
    • 长话短说,在 .c 文件中声明一个静态函数意味着它的范围仅限于所述 .c 文件,您不能在其他任何地方调用它

    【讨论】:

      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 2015-01-12
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      相关资源
      最近更新 更多