C/C++, can you #include a file into a string liter

2020-01-25 01:29发布

问题:

I have a C++ source file and a Python source file. I'd like the C++ source file to be able to use the contents of the Python source file as a big string literal. I could do something like this:

char* python_code = "
#include "script.py"
"

But that won't work because there need to be \'s at the end of each line. I could manually copy and paste in the contents of the Python code and surround each line with quotes and a terminating \n, but that's ugly. Even though the python source is going to effectively be compiled into my C++ app, I'd like to keep it in a separate file because it's more organized and works better with editors (emacs isn't smart enough to recognize that a C string literal is python code and switch to python mode while you're inside it).

Please don't suggest I use PyRun_File, that's what I'm trying to avoid in the first place ;)

回答1:

The C/C++ preprocessor acts in units of tokens, and a string literal is a single token. As such, you can't intervene in the middle of a string literal like that.

You could preprocess script.py into something like:

"some code\n"
"some more code that will be appended\n"

and #include that, however. Or you can use xxd​ -i to generate a C static array ready for inclusion.



回答2:

This won't get you all the way there, but it will get you pretty damn close.

Assuming script.py contains this:

print "The current CPU time in seconds is: ", time.clock()

First, wrap it up like this:

STRINGIFY(print "The current CPU time in seconds is: ", time.clock())

Then, just before you include it, do this:

#define STRINGIFY(x) #x

const char * script_py =
#include "script.py"
;

There's probably an even tighter answer than that, but I'm still searching.



回答3:

The best way to do something like this is to include the file as a resource if your environment/toolset has that capability.

If not (like embedded systems, etc.), you can use a bin2c utility (something like http://stud3.tuwien.ac.at/~e0025274/bin2c/bin2c.c). It'll take a file's binary representation and spit out a C source file that includes an array of bytes initialized to that data. You might need to do some tweaking of the tool or the output file if you want the array to be '\0' terminated.

Incorporate running the bin2c utility into your makefile (or as a pre-build step of whatever you're using to drive your builds). Then just have the file compiled and linked with your application and you have your string (or whatever other image of the file) sitting in a chunk of memory represented by the array.

If you're including a text file as string, one thing you should be aware of is that the line endings might not match what functions expect - this might be another thing you'd want to add to the bin2c utility or you'll want to make sure your code handles whatever line endings are in the file properly. Maybe modify the bin2c utility to have a '-s' switch that indicates you want a text file incorportated as a string so line endings will be normalized and a zero byte will be at the end of the array.



回答4:

You're going to have to do some of your own processing on the Python code, to deal with any double-quotes, backslashes, trigraphs, and possibly other things, that appear in it. You can at the same time turn newlines into \n (or backslash-escape them) and add the double-quotes on either end. The result will be a header file generated from the Python source file, which you can then #include. Use your build process to automate this, so that you can still edit the Python source as Python.



回答5:

You could use Cog as part of your build process (to do the preprocessing and to embed the code). I admit that the result of this is probably not ideal, since then you end up seeing the code in both places. But any time I see the "Python," "C++", and "Preprocessor" in closs proximity, I feel it deserves a mention.



回答6:

Here is how automate the conversion with cmd.exe

------ html2h.bat ------

@echo off
echo const char * html_page = "\
sed "/.*/ s/$/ \\n\\/" ../src/page.html | sed s/\"/\\\x22/g 
echo.
echo ";

It was called like

cmd /c "..\Debug\html2h.bat" > "..\debug\src\html.h"

and attached to the code by

#include "../Debug/src/html.h"
printf("%s\n", html_page);

This is quite system-dependent approach but, as most of the people, I disliked the hex dump.



回答7:

Use fopen, getline, and fclose.