繁体   English   中英

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

[英]Why does inline function need to be declared static if it uses fprintf?

我正在重构一些C代码并对因子部分进行单元测试(使用Google Test)。 在循环中多次使用了一个片段,因此为了将其暴露给测试,我将其作为头文件demo.hinline函数进行了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_ */

我的测试代码

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

此代码在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);
    }
}

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

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

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

对'print_line'的未定义引用

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

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

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

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

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

所以,在这种情况下,编译器抱怨你的非静态的内联函数调用不同的功能,这是static ,它是不知道这等函数( fprintf )不发生变异静态存储。

首先, inline行为,特别是涉及所涉及符号的链接,在C到C ++中是不同的。 (ISO C和GNU C之间也有所不同)。

你可以在这里阅读C版本。

如果您尝试将函数体放在C和C ++中包含的标题中(在同一个项目中),那么您将打开一堆真正的蠕虫。 两种语言标准均未涵盖这种情况。 实际上,我会将其视为ODR违规,因为该函数的C版本与C ++版本不同。

安全的做法是在头文件中只包含函数原型,并在其中一个非头文件源文件中包含函数体。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM