【问题标题】:with extern C but "has not had a body defined" error使用 extern C 但“尚未定义主体”错误
【发布时间】:2022-10-20 11:08:17
【问题描述】:

我有一个没有测试的 C 库A,我正在尝试为其函数funC 添加测试:

funC 中未在A/lib.h 中声明,而仅在A/lib.c 中声明:

static int funC();

static int funC(){
    // do something
}

我在test/A.t.cpp 中创建了一个测试文件,并想访问 funC 来测试它。 funC 仅在 .c 文件中声明,因此我决定使用extern C。在test/A.t.cpp 我有:

extern "C"{
    static int funC();
}

TEST(A,test){
    funC();
    .....
}

我认为使用 .t.cpp 文件中的声明,它将能够链接到 .c 文件中的实际实现,因此我应该能够调用该函数并对其进行测试,但我得到了:

Error: The function funC() has not had a body defined

我该如何解决?然后我还尝试在测试文件中添加实现并且它有效,但这不是我想要的。我希望 .t.cpp 文件链接到 .c 文件中的实际实现。谢谢!

【问题讨论】:

  • static 函数不是可见的在他们的编译单元之外......就是这样静止的方法...
  • @dbush 提供了一种可能性.... 或者,您可以“暂时”注释掉“静态”关键字,以便其他代码模块可以看到该功能.... 或者,您可以使用 #ifdef 隐藏无趣的功能并在同一个源文件中编写 C 测试代码。或者您可以调用该模块中依赖于该静态(辅助)函数的函数......许多测试方法......
  • 一个微妙的考虑单独测试静态函数时的考虑是您将绕过任何保护由使用静态函数的函数提供。编码人员可能没有费心去防御空指针、被零除或求负数的平方根,因为其他函数已经排除了将那种坏数据传递给静态函数的可能性……这不仅仅是推动的问题它直到它破裂......它可能是静态的......
  • 按照 dbush 的建议,您可以创建一个包含 A/lib.c 的文件 wrapper.c,然后提供一个调用 funcC 的函数,例如int funcC_wrapper() { return funcC(); }。然后测试代码调用funcC_wrapper()

标签: c++ c unit-testing googletest extern


【解决方案1】:

您的函数funC() 具有内部链接(这是static 用于C 中的函数和文件范围变量的含义)。除了定义它的翻译单元(无论是 C 还是 C++)之外,不能从其他翻译单元按名称调用它。

在您的测试源中,相同的名称指的是不同的功能,您尚未为其提供定义。

如果您希望funC() 可以从您的单独测试文件中调用,那么您应该通过删除其static 限定符或将其更改为extern 将其更改为具有外部链接。您将需要对测试文件中的声明进行相同的更改。

【讨论】:

  • @CPP,如果该函数不是公共的,那么您不能从另一个文件(包括定义测试的文件)调用它(按名称)。您的选择是(i)不要(直接)测试它; (ii) 通过提供外部链接将其公开;或 (iii) 做某事真的hacky,例如偷偷指向它的指针,或#include将其源文件放入您的测试源。就我而言,提供可测试性是为函数提供外部链接的正当理由,但 YMMV。
  • 谢谢。我不知道测试目的是否是公开私有函数的正当理由……这值得商榷
【解决方案2】:

要对静态函数进行单元测试,这是需要包含 .c 文件的罕见情况之一:

extern "C"{

#include "A/lib.c"

}

TEST(A,test){
    funC();
    .....
}

然后static 函数和变量将在测试代码中可见。

【讨论】:

  • @CPP然后你做错了什么。测试 A/lib.c 中代码的模块应该测试只要那个代码。
  • 抱歉,这是个坏主意。众所周知,C 和 C++ 是不同的语言。假设 C 代码可以成功编译为 C++,或者如果它编译成功,这意味着它与编译为 C 时的含义相同。对于用 C 编写的测试,我不会真正推荐它,但对于用 C++ 编写的测试,它从根本上是有缺陷的。
  • @CPP不,你会保持 A/lib.c 原样,而 test/A.t.cpp 会只要包含测试这些功能所需的代码。实际上提出了一个很好的观点。您应该在 C 模块中测试 C 代码,而不是 C++ 模块,因为它的行为可能不同。
  • @CPP这完全取决于您拥有的测试代码以及​​遇到的错误。如果可以用 C 而不是 C++ 编写测试代码,你应该这样做。
猜你喜欢
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-05-03
  • 2012-06-17
  • 2013-04-01
  • 1970-01-01
相关资源
最近更新 更多