2

我有一个要包含在另一个 cpp 文件中的头文件。我想知道如果我这样写头文件有什么区别,

#include <iostream>
#include <string>
using namespace std;

string ret()
{
return "called";
}

====================================

#include <iostream>
#include <string>
using namespace std;

static string ret()
{
return "called";
}

ret()无论如何我都可以访问该功能!那么,静电有什么用呢?

4

4 回答 4

5

这是你展示的一个非常邪恶的头文件。

  1. 永远不要放入using namespace std;头文件。这会强制包括标头在内的任何人都std在全局命名空间中拥有所有内容。

  2. 使用某种形式的包含守卫。

  3. static使函数在.cpp包含它的位置之外不可见。这意味着每个.cpp包含标头的内容都将拥有自己的函数副本。static仅当您特别需要此行为时才应使用(非成员)函数。

  4. 如果您不使用static,您应该将定义从头文件移动到源文件中(如果您希望它定义一次),或者声明函数inline(如果可能,它的代码将被内联到每个调用站点上)。如果您不执行上述任何一项操作,如果您在多个源文件中包含标头,则会出现多个定义错误。

于 2013-01-08T09:06:46.107 回答
4

第一个头文件定义了一个ret在包含它的每个翻译单元中使用外部链接调用的函数。如果在同一个程序中链接了多个这样的 TU,则这是不正确的。

第二个头文件定义了一个ret在包含它的每个翻译单元中使用内部链接调用的函数。这意味着每个 TU 都有自己的函数的私有副本(具有不同的地址),无论有多少链接在一起。

使用头文件共享代码的正确方法有以下三种:

  • 具有内部链接的函数(如在您的第二个标头中,或在 C++11 中将其放在无名命名空间中)。
  • 具有外部链接的内联函数(替换staticinline)。的意思inline是,虽然程序中函数只有一个副本,但是每一个使用函数的TU都包含了它的定义。
  • 在头文件中声明函数,并在其中准确定义一个 .cpp 文件(例如 ret.cpp)。

在 C++03 中有第四种方式:

  • 在无名命名空间中具有外部链接的函数

我相信这在 C++11 中仍然可用,但在 C++11 中,无名命名空间中的函数默认具有内部链接。我不知道在 C++11 中使无名命名空间中的函数具有外部链接的任何用途。因此,就函数而言,无名命名空间是提供函数内部链接的好方法。

您使用哪一种取决于您的需求。第三个选项意味着您可以在不重新编译调用代码的情况下更改函数的定义,尽管您仍然需要重新链接可执行文件,除非该函数位于 dll 中。

如果出现以下情况,前两个 (staticinline) 的行为会有所不同:

  • 该函数包含static局部变量,
  • 您比较ret不同 TU 中的函数指针,
  • 你检查你的可执行文件大小或符号表,
  • 不同的 TU 中函数的定义是不同的(可能是由于不同的#defines),如果函数有外部链接是禁止的,如果是内部的则不是。

否则,它们几乎相同。

根据标准,inline也暗示编译器应该优化对该函数的调用以快速执行(这实际上意味着在调用站点内联代码)。大多数编译器大部分时间都会忽略这个提示。如果他们将一个staticinline函数评估为内联的好候选者,他们会很乐意内联它,如果他们评估一个函数是内联的不好候选者,他们将很乐意避免内联inline函数。

于 2013-01-08T09:06:55.370 回答
2

使用头卫。

不要在头文件中使用“使用命名空间”。(实际上,不要在头文件中使用“using”。使用完全限定的标识符。)

并使用标头来声明函数,而不是定义它们。您将希望代码ret()只出现在生成的可执行文件中一次。您可以通过将 的定义(代码)ret()放入 .cpp 文件中来实现这一点。一个.cpp 文件,而不是多个文件(通过包含定义)。

头文件列出了函数的声明ret(),以便其他代码“知道”该函数存在、它采用哪个参数以及它返回什么。

于 2013-01-08T09:09:33.517 回答
1

如果您在头文件中定义 c++ 方法static,则每个翻译单元(包含该头文件的每个 .cpp 文件)将具有这些静态方法的不同版本 - 它们将不具有相同的地址空间。因此,您的程序的大小将不必要地增加。

另外,为了清楚起见:

将方法定义为static仅在 .cpp 文件中意味着该方法具有静态链接,并且只能从同一 .cpp 文件中的其他方法访问。

于 2013-01-08T09:15:43.850 回答