简体   繁体   中英

How can I make the contents of an #include-file a compile-time constant in a cpp-file?

I have a file module.hpp

struct ModuleBase {
    virtual void run() = 0;
};

and a main.cpp program

int main() {
    cout << ...?...; // here should go the contents of module.hpp
}

What can I put at ...?... to let the contents of the header file printed here?

A basic idea would be

int main() {
    static const string content = R"(
#include <module.hpp>
)";
    cout << content;
}

but multi-line-strings are only available in C++11, and #include does not work inside multi-line strings (which is good)?

If there is a non-portable way for the gcc... that would be a start.

Clarification (update): The substitution should be done at compile time.

The only real solution I know is to write a small program which converts a file into a C++ definition of a string variable containing it. This is fairly simple to write: output a simple header along the lines of:

char const variableName[] =

Then copy each line of the file, wrapping it in "...\\n" , and escaping any characters necessary. (If you can be sure of C++11, then you might be able to do something with R"..." , but I've no experience with this.)

[update: refering to the original question with a typo in it]: Your solution should not work; if it does, it is an error in the compiler. According to §2.2, tokenization occurs before the execution of preprocessing directives. So when the execution of preprocessing directives occurs, you have a string literal, and not a # preprocessing token. (Compiler errors are to be expected when using C++11 features. There's not been enough time yet for the implementers to get all of the bugs out.)

As a GNU-only hack, you could convert the header into a binary object file and link that with the executable.

First, use objcopy to do the conversion:

objcopy -I binary -O default -B i386 module.hpp module.hpp.o 

replacing i386 with the architecture you're building for if necessary. The resulting object file will contain symbols for the header contents and its size, which you can access as follows:

#include <iostream>

extern char _binary_module_hpp_start;
extern char _binary_module_hpp_size;

int main()
{
    char * header_start = &_binary_module_hpp_start;
    size_t header_size = reinterpret_cast<size_t>(&_binary_module_hpp_size);

    std::cout.write(header_start, header_size);
}

Apart from external tools, I think it cannot be done. The C++11 way you given does not work, #include is not expanded in a string. See here for example .

The C++03 way would have been the following, with macros:

#define TO_STR__(...) #__VA_ARGS__
#define TO_STR_(...) TO_STR__(__VA_ARGS__)
#define TO_STR(...) TO_STR_(__VA_ARGS__)

#include <iostream>
int main()
{
    std::cout << "String from #include <string>, ";
    static const char* str = TO_STR(
#include <string>
    );

    std::cout << sizeof(str) / sizeof(char) << " characters:\n\n";
    std::cout << str << "\n";
}

With GCC , nothing is outputed. With Visual Studio 2010, #include <string> is outputed.

If you can modify the compilation chain, you can add a prebuild step which will include the contents of the file you want as a string (can be done easily with tools like CMake, or custom makefile).

您可以使用ofstream打开文件流并读取和输出内容。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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