Why should an inline function be declared static if it uses fprintf?

I am reorganizing some C code and doing unit testing on the factored parts (using Google Test). One fragment was used several times in the loop, so to test it, I considered it as an inline function in the demo.h header demo.h , which also includes declarations of some other inline functions. A simplified version is as follows:

 #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_ */ 

My test code

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

This code compiles and works fine under MinGW g ++ 4.8.1 with -std=gnu++0x .

C source code uses this function. The simplified version will be as follows:

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

However, when I try to compile my C code using MinGW GCC 4.8.1 with -std=c99 , I get the following warning:

warning: 'fprintf' is static, but used in the built-in function 'print_line' which is not static [enabled by default]

I also get the following error, which may be related:

undefined link to `print_line '

Changing the signature in the header to static inline void print_line ... problem. However, I do not like not to understand the cause of the problem. Why did the lack of static not affect the C ++ test? And what does the error regarding fprintf really mean?

+6
source share
2 answers

Without static you allow the C99 compiler to create both an external-linked function (defined in one place) and a separate inline code in each translation unit containing the file. He can use any function that he likes, unless you explicitly decide between static or extern .

One requirement for such features can be seen in C99 Draft 6.7.4.3 :

The built-in definition of a function with an external link must not contain a definition of a modifiable object with a static storage duration and should not contain a link to an identifier with an internal link.

This makes sense because the compiler wants this function to behave the same, no matter how it wants to implement it.

So, in this case, the compiler complains that your non-static built-in function calls another function, which is static , and not sure if this other function ( fprintf ) does not mutate the static storage.

+6
source

First of all, the behavior of inline , especially with regard to the relationship of the characters involved, differs from C to C ++. (And also different between ISO C and GNU C).

You can read about version C here.

If you try to put the body of the function in a header that is included with both C and C ++ (within the same project), you open a real can of worms. This situation does not apply to any of the language standards. In practical terms, I would consider this a violation of ODR , because the C version of the function is different from the C ++ version.

The safe thing is to include only the function prototype in the header and have the body of the function in one of the source files without a header.

+4
source

All Articles