如果内联函数使用fprintf,为什么需要声明为static?

bel*_*daz 9 c c++ static inline

我正在重构一些C代码并对因子部分进行单元测试(使用Google Test).在循环中多次使用了一个片段,因此为了将其暴露给测试,我将其作为inline头文件中的函数进行了考虑,该头文件demo.h还包括一些其他非inline函数的声明.简化版如下:

#ifndef DEMO_H_
#define DEMO_H_
#ifdef __cplusplus
extern "C" {
#endif
inline void print_line(FILE* dest, const double * data, int length) {
    for (int s = 0; s < length; s++)
        fprintf(dest, "%lf ", data[s]);
    fprintf(dest, "\n");
}
#ifdef __cplusplus
}
#endif
#endif /* MK_H_ */
Run Code Online (Sandbox Code Playgroud)

我的测试代码

#include "gtest/gtest.h"
#include "demo.h"
#include <memory>
#include <array>
#include <fstream>

TEST (demo, print_line) {
    std::array<double,4> test_data = {0.1, 1.4, -0.05, 3.612};

    const char* testfile = "print_line_test.txt";
    {
        auto output_file = std::unique_ptr<FILE, decltype(fclose)*>{
            fopen(testfile, "w"), fclose };
        print_line(output_file.get(), test_data.data(), test_data.size());
    }

    std::ifstream input(testfile);
    double dval;
    for(const auto& v: subsequence_data) {
        input >> dval;
        EXPECT_EQ (v, dval);
    }
    EXPECT_FALSE (input >> dval) << "No further data";
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
Run Code Online (Sandbox Code Playgroud)

此代码在MinGW g ++ 4.8.1下编译并运行正常-std=gnu++0x.

然后原始C代码使用此功能.简化版本如下:

#include "demo.h"

void process_data(const char* fname, double ** lines, int num_lines, int line_length) {
    FILE* output_file = fopen(fname, "w");
    for (int i=0; i<num_lines; ++i) {
      print_line(output_file, lines[i], line_length);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试使用MinGW GCC 4.8.1编译我的C代码时-std=c99,我收到以下警告:

警告:'fprintf'是静态的,但在内联函数'print_line'中使用,它不是静态的[默认启用]

我也得到一个后续错误,这可能是相关的:

对'print_line'的未定义引用

更改标题中的签名static inline void print_line ...似乎可以解决问题.但是,我不喜欢不了解问题的原因.为什么缺乏static不影响C++测试?那个错误fprintf究竟意味着什么呢?

Gro*_*roo 7

如果没有static,您允许C99编译器创建具有外部链接的函数(在单个位置定义),但在包含该文件的每个转换单元中也分别使用内联代码.它可以使用它喜欢的任何功能,除非你明确地在static或之间做出决定extern.

C99草案6.7.4.3中可以看到这些功能的一个要求:

具有外部链接的函数的内联定义不应包含具有静态存储持续时间的可修改对象的定义,并且不应包含对具有内部链接的标识符的引用.

这是有道理的,因为编译器希望此函数的行为相同,无论它选择如何实现它.

因此,在这种情况下,编译器抱怨你的非静态内联函数正在调用一个不同的函数static,并且它不确定这个其他函数(fprintf)不会改变静态存储.

  • 谢谢,这具体回答了我所观察到的问题,并有助于解释那个令人不安的警告。 (2认同)