如果同一工作区中的两个独立源文件共享函数名称,为什么 C 无法编译?
Why won't C compile if two separate source files in the same workspace share function names?
我在项目中使用 eclipse indigo、gcc 和 cdt。如果不同源文件中的两个函数共享名称(无论 return 类型或参数如何),eclipse 会标记重定义错误。对于这个项目来说,这不是一个大问题,因为我可以轻松地重命名这些函数,而且如果是的话,我很清楚包装器。虽然这不是一个关键问题,但它确实让我觉得我不了解 c 构建过程。在构建过程中会发生什么,这样的程序结构会导致问题?
这里有更多信息。关于情况,以及到目前为止我的理解 - 没有必要回答这个问题,尽管我的理解肯定有漏洞。
在这种情况下,这两个函数旨在仅在本地使用,因此它们的原型未在 .h 接口中给出,并且为了我的观点,两者都没有定义 'static'。
这些源文件均未包含在项目的任何位置,因此它们不应共享任何编译单元。考虑到这一点,我会假设两个源文件都不知道另一个源文件的存在,并且编译器在索引这两个函数时不会有问题,因为单独的文件可以在链接期间正确区分两者 - - 只要它们不包含在同一个编译单元中。
我注意到静态定义函数声明的任一实例可以消除错误。我记得在某个时候读到每个未声明为静态的函数都是全局的——尽管考虑到这些函数不是 .h 接口的一部分,但包含 .h 接口的实际示例不允许包含程序引用所有 .c 函数都表明 "hiding" 这些函数没有问题。
我忽略了什么?
不胜感激,谢谢!
remember reading at some point that every function not declared static is global
了解了这一点后,您就了解了观察到的行为的要点和原因。
.h 文件是链接器不知道的,在预处理后只剩下翻译单元(通常是一个 .c 文件,所有的 include 都合并进来),.o 文件是从中编译的。
C 中没有语言级别的接口。
Neither of these source files are being included anywhere in the project, so they shouldn't be sharing any compilation units.
将这些函数声明为 static
。这是从链接器 "inside" 翻译单元 "hide" 函数的唯一方法。
一个源模块是否包含另一个源模块的 headers 并不重要。 Header 文件仅包含用于局部函数能够在其他模块中找到函数的目的的声明。这并不意味着从该模块的角度来看,未声明的函数不存在。
当所有内容链接在一起时,任何未明确定义为本地源模块的内容(即 static
)必须在所有链接组件中具有唯一名称。
这是"linkage"的概念。 C 中的每个函数和变量都有一个链接类型,"external"、"internal" 和 "none" 之一。 (只有变量可以没有链接。)
函数默认具有外部链接,这意味着它们可以从任何编译单元按名称调用(其中 "compilation unit" 大致表示一个源文件及其包含的所有头文件)。这可以通过声明它们 extern
来明确表达,也可以通过声明它们 static
来覆盖。声明的函数 static
具有内部链接,这意味着它们只能通过名称从同一编译单元中的其他函数引用。
无论头文件如何,同一程序中任何位置的两个外部函数都不能同名,但不同编译单元中的静态函数可以同名。静态函数也可能与外部函数具有相同的名称——然后该名称在其编译单元内解析为静态函数,并在其他地方解析为外部函数。这些限制是有道理的,否则函数调用可能会产生歧义。
头文件根本不影响链接方程。它们主要是共享声明的工具,但函数的链接仅取决于 how 它是如何声明的,而不是 where.
我下次再讨论变量的联系。
C 不像 C++ 或 Java 那样 "mangle" 函数命名(因为 C 不支持函数多态性)。
例如,在 C++ 中,函数
void foo( void );
void foo( int x );
void foo( int x, double y );
将他们的名字"mangled"转化为独一无二的符号1
_Z3fooid
_Z3fooi
_Z3foov
这就是超载 function/method 调用在机器级别消除歧义的方式。
C 不会那样做;相反,链接器会看到两个使用相同符号和 yaks 的不同函数定义,因为它无法消除这两者的歧义。
1。无论如何,这就是我系统上发生的事情
我在项目中使用 eclipse indigo、gcc 和 cdt。如果不同源文件中的两个函数共享名称(无论 return 类型或参数如何),eclipse 会标记重定义错误。对于这个项目来说,这不是一个大问题,因为我可以轻松地重命名这些函数,而且如果是的话,我很清楚包装器。虽然这不是一个关键问题,但它确实让我觉得我不了解 c 构建过程。在构建过程中会发生什么,这样的程序结构会导致问题?
这里有更多信息。关于情况,以及到目前为止我的理解 - 没有必要回答这个问题,尽管我的理解肯定有漏洞。
在这种情况下,这两个函数旨在仅在本地使用,因此它们的原型未在 .h 接口中给出,并且为了我的观点,两者都没有定义 'static'。
这些源文件均未包含在项目的任何位置,因此它们不应共享任何编译单元。考虑到这一点,我会假设两个源文件都不知道另一个源文件的存在,并且编译器在索引这两个函数时不会有问题,因为单独的文件可以在链接期间正确区分两者 - - 只要它们不包含在同一个编译单元中。
我注意到静态定义函数声明的任一实例可以消除错误。我记得在某个时候读到每个未声明为静态的函数都是全局的——尽管考虑到这些函数不是 .h 接口的一部分,但包含 .h 接口的实际示例不允许包含程序引用所有 .c 函数都表明 "hiding" 这些函数没有问题。
我忽略了什么?
不胜感激,谢谢!
remember reading at some point that every function not declared static is global
了解了这一点后,您就了解了观察到的行为的要点和原因。
.h 文件是链接器不知道的,在预处理后只剩下翻译单元(通常是一个 .c 文件,所有的 include 都合并进来),.o 文件是从中编译的。
C 中没有语言级别的接口。
Neither of these source files are being included anywhere in the project, so they shouldn't be sharing any compilation units.
将这些函数声明为 static
。这是从链接器 "inside" 翻译单元 "hide" 函数的唯一方法。
一个源模块是否包含另一个源模块的 headers 并不重要。 Header 文件仅包含用于局部函数能够在其他模块中找到函数的目的的声明。这并不意味着从该模块的角度来看,未声明的函数不存在。
当所有内容链接在一起时,任何未明确定义为本地源模块的内容(即 static
)必须在所有链接组件中具有唯一名称。
这是"linkage"的概念。 C 中的每个函数和变量都有一个链接类型,"external"、"internal" 和 "none" 之一。 (只有变量可以没有链接。)
函数默认具有外部链接,这意味着它们可以从任何编译单元按名称调用(其中 "compilation unit" 大致表示一个源文件及其包含的所有头文件)。这可以通过声明它们 extern
来明确表达,也可以通过声明它们 static
来覆盖。声明的函数 static
具有内部链接,这意味着它们只能通过名称从同一编译单元中的其他函数引用。
无论头文件如何,同一程序中任何位置的两个外部函数都不能同名,但不同编译单元中的静态函数可以同名。静态函数也可能与外部函数具有相同的名称——然后该名称在其编译单元内解析为静态函数,并在其他地方解析为外部函数。这些限制是有道理的,否则函数调用可能会产生歧义。
头文件根本不影响链接方程。它们主要是共享声明的工具,但函数的链接仅取决于 how 它是如何声明的,而不是 where.
我下次再讨论变量的联系。
C 不像 C++ 或 Java 那样 "mangle" 函数命名(因为 C 不支持函数多态性)。
例如,在 C++ 中,函数
void foo( void );
void foo( int x );
void foo( int x, double y );
将他们的名字"mangled"转化为独一无二的符号1
_Z3fooid
_Z3fooi
_Z3foov
这就是超载 function/method 调用在机器级别消除歧义的方式。
C 不会那样做;相反,链接器会看到两个使用相同符号和 yaks 的不同函数定义,因为它无法消除这两者的歧义。
1。无论如何,这就是我系统上发生的事情