views:

1658

answers:

7

Is there a way to include an entire text file as a string in a C program at compile-time?

something like:

  • file.txt:

    This is
    a little
    text file
    
  • main.c:

    #include <stdio.h>
    int main(void) {
       #blackmagicinclude("file.txt", content)
       /*
       equiv: char[] content = "This is\na little\ntext file";
       */
       printf("%s", content);
    }
    

obtaining a little program that prints on stdout "This is a little text file"

At the moment I used an hackish python script, but it's butt-ugly and limited to only one variable name, can you tell me another way to do it?

A: 

Take a look here for reading a file into a char[].

http://stackoverflow.com/questions/410943/reading-a-text-file-into-an-array-in-c

Here are some tips for using the C preprocessor's macros.

http://gcc.gnu.org/onlinedocs/cpp/Macros.html

Daniel A. White
Sorry. I thought you needed it at runtime.
Daniel A. White
+1  A: 

What might work is if you do something like:

int main()
{
    const char* text = "
#include "file.txt"
";
    printf("%s", text);
    return 0;
}

Of course you'll have to be careful with what is actually in the file, making sure there are no double quotes, that all appropriate characters are escaped, etc.

Therefore it might be easier if you just load the text from a file at runtime, or embed the text directly into the code.

If you still wanted the text in another file you could have it in there, but it would have to be represented there as a string. You would use the code as above but without the double quotes in it. For example:

"Something evil\n"\
"this way comes!"

int main()
{
    const char* text =
#include "file.txt"
;
    printf("%s", text);
    return 0;
}
Daemin
Nice idea but it won't work, either you have an error because the literal includes a new-line or the #include part will be read as a string and not executed, damned if you do and damned if you don't...
Motti
@Motti: agreed - as written, syntactically invalid C. The idea is interesting - the C Pre-Processor is logically a separate phase - but the practice is that it doesn't get off the ground because each line in the included file would have to end with a backslash, etc.
Jonathan Leffler
Humm.Seems to me that you should not need the backslash as most compilers will concatenate adjecent strings together
EvilTeach
A: 

Even if it can be done at compile time (I don't think it can in general), the text would likely be the preprocessed header rather than the files contents verbatim. I expect you'll have to load the text from the file at runtime or do a nasty cut-n-paste job.

Daniel Paull
+15  A: 

I'd suggest using (unix util)xxd for this. you can use it like so

$ echo hello world > a
$ xxd -i a

outputs:

unsigned char a[] = {
  0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
Hasturkun
Just a note: the char[] created by xxd isn't NULL-terminated!so I do $ xxd -i < file.txt > file.xxd $ echo ', 0' >> file.xxdand in the main.c char file_content[] = { #include "file.xxd" };
I never knew about xxd. It's awesome!
Anthony Cuozzo
@Hasturkun: I understand how you generated the output using `xxd`. What I do not understand is how are you going to include `xxd` in your C code. After all `xxd` is a shell command. How are you going to use it from within a C program??
Lazer
@eSKay: you do not include `xxd` in your code, you include the output of `xxd` in your code. eg. you can run something like `xxd -i inputfile outputfile.h` and later `#include "outputfile.h"`
Hasturkun
@Hasturkun: How will you get the `unsigned char a[] = {` and `}` parts?
Lazer
@eSKay: that comes directly from the output of `xxd`, as the answer says. the name of the array is the input filename. if you're piping data in instead of using an input file, you'll get an list of hexadecimal values instead (without the array declaration or the len variable).
Hasturkun
+2  A: 

You have two possibilities:

  1. Make use of compiler/linker extensions to convert a file into a binary file, with proper symbols pointing to the begin and end of the binary data. See this answer: Include binary file with GNU ld linker script.
  2. Convert your file into a sequence of character constants that can initialize an array. Note you can't just do "" and span multiple lines. You would need a line continuation character (\), escape " characters and others to make that work. Easier to just write a little program to convert the bytes into a sequence like '\xFF', '\xAB', ...., '\0' (or use the unix tool xxd described by another answer, if you have it available!):

Code:

#include <stdio.h>

int main() {
    int c;
    while((c = fgetc(stdin)) != EOF) {
        printf("'\\x%X',", (unsigned)c);
    }
    printf("'\\0'"); // put terminating zero
}

(not tested). Then do:

char my_file[] = {
#include "data.h"
};

Where data.h is generated by

cat file.bin | ./bin2c > data.h
Johannes Schaub - litb
last line should probably read "cat file.bin | ./bin2c > data.h"or "./bin2c < file.bin > data.h"
Hasturkun
Hasturkun, thanks
Johannes Schaub - litb
A: 

ok, inspired by Daemin's post i tested the following simple example :

a.data:

"this is test\n file\n"

test.c:

int main(void)
{
    char *test = 
#include "a.data"
    ;
    return 0;
}

gcc -E test.c output:

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.c"

int main(void)
{
    char *test =
# 1 "a.data" 1
"this is test\n file\n"
# 6 "test.c" 2
    ;
    return 0;
}

So it's working but require data surrounded with commas.

Ilya
That's what I was alluding to in the last bit of my answer.
Daemin
Full credit given :)
Ilya
Data surrounded by _commas_?
bdonlan
quotation, or whatever it's called, pardon my English
Ilya
A: 

in x.h

"this is a "
"buncha text"

in main.c

#include <stdio.h>
int main(void)
{
    char *textFileContents =
#include "x.h"
    ;

    printf("%s\n", textFileContents);

    return 0
}

ought to do the job.

EvilTeach