第一个头文件定义了一个ret
在包含它的每个翻译单元中使用外部链接调用的函数。如果在同一个程序中链接了多个这样的 TU,则这是不正确的。
第二个头文件定义了一个ret
在包含它的每个翻译单元中使用内部链接调用的函数。这意味着每个 TU 都有自己的函数的私有副本(具有不同的地址),无论有多少链接在一起。
使用头文件共享代码的正确方法有以下三种:
- 具有内部链接的函数(如在您的第二个标头中,或在 C++11 中将其放在无名命名空间中)。
- 具有外部链接的内联函数(替换
static
为inline
)。的意思inline
是,虽然程序中函数只有一个副本,但是每一个使用函数的TU都包含了它的定义。
- 在头文件中声明函数,并在其中准确定义一个 .cpp 文件(例如 ret.cpp)。
在 C++03 中有第四种方式:
我相信这在 C++11 中仍然可用,但在 C++11 中,无名命名空间中的函数默认具有内部链接。我不知道在 C++11 中使无名命名空间中的函数具有外部链接的任何用途。因此,就函数而言,无名命名空间是提供函数内部链接的好方法。
您使用哪一种取决于您的需求。第三个选项意味着您可以在不重新编译调用代码的情况下更改函数的定义,尽管您仍然需要重新链接可执行文件,除非该函数位于 dll 中。
如果出现以下情况,前两个 (static
或inline
) 的行为会有所不同:
- 该函数包含
static
局部变量,
- 您比较
ret
不同 TU 中的函数指针,
- 你检查你的可执行文件大小或符号表,
- 不同的 TU 中函数的定义是不同的(可能是由于不同的#defines),如果函数有外部链接是禁止的,如果是内部的则不是。
否则,它们几乎相同。
根据标准,inline
也暗示编译器应该优化对该函数的调用以快速执行(这实际上意味着在调用站点内联代码)。大多数编译器大部分时间都会忽略这个提示。如果他们将一个static
非inline
函数评估为内联的好候选者,他们会很乐意内联它,如果他们评估一个函数是内联的不好候选者,他们将很乐意避免内联inline
函数。