c++ - 为什么使用 fprintf 的内联函数需要声明为静态的?

标签 c++ c static inline

我正在重构一些 C 代码并对分解出的部分执行单元测试(使用 Google 测试)。一个片段在一个循环中被多次使用,所以为了将它暴露给测试,我将它分解为头文件 demo.h 中的 inline 函数,其中还包括一些其他非 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_ */

我的测试代码

#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();
}

这段代码在带有 -std=gnu++0x 的 MinGW g++ 4.8.1 下编译和运行良好。

原来的 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);
    }
}

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

warning: 'fprintf' is static but used in inline function 'print_line' which is not static [enabled by default]

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

undefined reference to `print_line'

将 header 中的签名更改为 static inline void print_line ... 似乎可以解决问题。但是,我不喜欢不了解问题的原因。为什么缺少static不影响C++测试?关于 fprintf 的错误实际上意味着什么?

最佳答案

如果没有 static,您将允许 C99 编译器创建具有外部链接的函数(在一个地方定义),而且在包含该文件的每个翻译单元中创建单独的内联代码。它可以使用它喜欢的任何函数,除非您明确选择 staticextern

这些功能的一个要求可以在C99 Draft 6.7.4.3中看到。 :

An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static storage duration, and shall not contain a reference to an identifier with internal linkage.

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

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

关于c++ - 为什么使用 fprintf 的内联函数需要声明为静态的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35003070/

相关文章:

java - 将静态方法放在接口(interface)中是一种好习惯吗?

C#:Cdecl DllExport,参数中带有指向类实例的指针

c++ - 模板友元函数实例化

c++ - 我应该/可以/必须如何处理我的 C++ 项目所依赖的 dll?

c - LD_PRELOAD不会影响RTLD_NOW的dlopen()

c - 在 xcode 中运行 c 什么也没显示

c - OpenSSL DigestInit_ex

java - Java 中静态变量的延迟初始化 - 执行?

c++ - 在 C++ 中从文件中尽可能快地读取键值对

java - java中的二维数组静态初始化