简体   繁体   中英

Printing the contents of a file using the #include directive (preprocessor)

Say I have a file, t.txt, that contains the following two lines:

one    
two

Now, I would like to write a program which will #include that file somehow and print its contents, nothing more. That is, I want the contents of that file to appear in my code as a static text, at compile time.

Any ideas?


The reason im asking is this:

I would like to create a quine by including my own file (with ifndefs to prevent recursive inclusion after the first two): http://en.wikipedia.org/wiki/Quine_(computing) . So I'd still love to get an answer.

Alternative solution (since the original one won't work without limitations, as mentioned in the comments): As part of your build process, use a script (perl or python would do it easily) to generate staticstring.h from staticstring.txt , adding quotes and \\n 's as necessary, then use the other solution. This way your original file does not change.

You want to change

Text file with text
on multiple
lines

to

"Text file with text\n"
"on multiple\n"
"lines"

I think that doing it purely with the preprocessor is not possible.

This is the Microsoft Tutorial to do that: http://support.microsoft.com/kb/816181/en-us

It is not explaining how to embedd the file programatically or via preprocessor, but via the Visual Studio 2005+ menus. And explains how to read it back from the resources sector.

Borland Delphi does that via preprocessor, I don't know about C++. But I know it is possible to edit the resources by hand and include it, just like the VS do.

xxd -i

看到这里: 以前的答案

Would something like this work for you?

example.c

static const char *var = 
#include "staticstring.txt"
;

int main() {
    printf( "%s\n" var );
    return 0;
}

staticstring.txt

"Some string that gets included at compile time"

I'm sure there's a way that you can do it without having the quotes inside the text file, but nothing is coming to mind right now.

You could do this in the makefile:

all:  target

TEXT_FILES  = $(wildcard *.txt)
TEXT_OBJS   = $(patsubst %.txt,%.text.o,$(TEXT_FILES))


target: main.o $(TEXT_OBJS)
    $(CXX) -o app $^

%.text.cpp: %.txt
    @echo "Building Text Source $*"
    @echo "char const* $* =" > $@
    @awk '{print "\"" $$0 "\\n\"";}' $^ >> $@
    @echo ";" >> $@

What this does.
If you have a text file called plop.txt. Then it creates a file plop.text.cpp with the variable 'char const* plop ='. Once compiled the temporary file is removed but if you change the plop.txt file it will be auto-magically be rebuilt into plop.text.o

This is then all combined together:

The following Example is what I tested:

> cat main.cpp

#include <iostream>
extern char* text;

int main()
{
std::cout << text;
}

> cat text.txt 

Hi there this is a file
with multiple lines
we want to print out.
> make
g++    -c -o main.o main.cpp
Building Text Source text
g++    -c -o text.text.o text.text.cpp
g++ -o app main.o text.text.o
rm text.text.cpp
> ./app

Hi there this is a file
with multiple lines
we want to print out.
> 

What I did was this:

COPYING.cc: ${top_srcdir}/COPYING
    echo "const char * COPYING = " >$@ || (rm $@;exit 1)
    sed -e 's/"/\\"/g' -e 's/^/\"/' -e 's/$$/\\n\"/' $< >>$@ || (rm $@;exit 1)
    echo ';' >>$@ || (rm $@;exit 1)

in my Makefile . I then referred to it as extern const char *COPYING , but one can #include it as well.

You can use objcopy to create an object file out of the source file and link it with the actual object file. It creates the symbols _binary_objfile_start, _binary_objfile_end and _binary_objfile_size , which you can access as an array of char.

As far as I'm aware, the shortest possible quine in C is this:

main(){char*a="main(){char*a=%c%s%c;printf(a,34,a,34);}";printf(a,34,a,34);}

Note that this is not valid C++, since it uses an implicit definition of printf() . To make it valid C++, you need to do this:

#include <stdio.h>
main(){char*a="#include <stdio.h>%cmain(){char*a=%c%s%c;printf(a,10,34,a,34);}";printf(a,10,34,a,34);}

No tricky include tricks -- just carefully constructing a string and printing it out twice, and using ASCII codes (10 and 34 instead of '\\n' and '"' ) to avoid annoyingness with having to escape stuff.

I don't believe it's going to be possible, as you can't #include an arbitrary text file in C. The reason is that there are no multi-line constants in C (although you can concatenate a number of single-line string constants).

The only options I can see are to require that each line of the text file be quoted, or generate a temporary file at build-time (as others have suggested).

tt:

printf ("int main () {\n");
printf ("#include <t.t>\n");
printf ("}");
return 0;

tc

int main () {
#include <t.t>
}


$ gcc -I. t.c
$ ./a.out
int main () {
#include <t.t>
} 

Update: If you are not after a pure quine, but just something that will spit out the contents of the included file, you can do the following:

tc:

#include <stdio.h>
#include "t.t"

tt:

#define FOO(f) do { \
        FILE * ff = fopen(f, "rb"); \
        char foo[255] = {0}; \
        while (fgets (foo, 255, ff)) { \
                printf ("%s", foo); \
        }\
        fclose(ff); \
} while (0)

int main () {
        FOO("t.t");
        return 0;
}

running this yields

$ gcc t.c
$ ./a.out
#define FOO(f) do { \
        FILE * ff = fopen(f, "rb"); \
        char foo[255] = {0}; \
        while (fgets (foo, 255, ff)) { \
                printf ("%s", foo); \
        }\
        fclose(ff); \
} while (0)

int main () {
        FOO("t.t");
        return 0;
}

It's very easy:

#include <stdio.h>

// include the file somehow
#define one 
#define two 
#include "t.txt"

int main(int argc, char* argv[])
{
    // and print the contents of the file
    const char* static_text = "one\ntwo\n";
    printf(static_text);

    // nothing more ;-)
    return 0;
}

Seriously, it's not possible to "#include" an arbitrary file. (Go with one of the preprocessing suggestions given in other answers if you need this.)

If the contents of the file is not arbitrary, but contains something meaningful to the compiler, you might be able to hack something together. To make the contents meaningful, you can use C code and/or define's as I did above.

  • Add resource file to your project.
  • Open resource editor by double clicking on resource file ({projectname}.rc).
  • In resource editor add custom type, for example CPPCODE.
  • Enter some binary data into binary content of that resource file.
  • Save all, and close resource editor.
  • Open {projectname}.rc file as code.
  • Locate CPPCODE and replace file path in quotes to file where your {projectname}.cpp file resides (relative path). It should look something like this:

Code:

IDR_FILE_DIRECTORYINFO_H    CPPCODE "DirectoryInfo.h"
IDR_FILE_DIRECTORYINFO_CPP  CPPCODE "DirectoryInfo.cpp"
  • Check resource.h does it contains correct #defines for IDR_FILE_DIRECTORYINFO_H, ..., if you have added additional entries:

Code:

#define IDR_FILE_DIRECTORYINFO_H        312
#define IDR_FILE_DIRECTORYINFO_CPP      313
  • Access, and print resource content:

Code:

HRSRC hRes = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FILE_DIRECTORYINFO_CPP), _T("CPPCODE"));
DWORD dwSize = SizeofResource(GetModuleHandle(NULL), hRes);
HGLOBAL hGlob = LoadResource(GetModuleHandle(NULL), hRes);
const char* pData = reinterpret_cast<const char*>(::LockResource(hGlob));

MessageBoxA((HWND)0, pData, "This project source code:", MB_OK);

And that's it

Al trough I don't see any point in Quine (computing). Polymorphism is another story ;) have fun.

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