¿Hay alguna manera de incluir un archivo de texto completo como una cadena en un programa C en tiempo de compilación?
algo como:
file.txt:
This is a little text file
C Principal:
#include <stdio.h> int main(void) { #blackmagicinclude("file.txt", content) /* equiv: char[] content = "This is\na little\ntext file"; */ printf("%s", content); }
obteniendo un pequeño programa que imprime en stdout "Este es un pequeño archivo de texto"
Por el momento utilicé un script de Python hackish, pero es feo y está limitado a un solo nombre de variable, ¿puede decirme otra forma de hacerlo?
c
include
c-preprocessor
Brian Tompsett - 汤 莱恩
fuente
fuente
Respuestas:
Sugeriría usar (unix util) xxd para esto. puedes usarlo así
salidas:
fuente
xxd
, como dice la respuesta. El nombre de la matriz es el nombre de archivo de entrada. si está ingresando datos en lugar de usar un archivo de entrada, obtendrá una lista de valores hexadecimales (sin la declaración de matriz o la variable len).xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
La pregunta era sobre C, pero en caso de que alguien intente hacerlo con C ++ 11, se puede hacer con solo pequeños cambios en el archivo de texto incluido gracias a los nuevos literales de cadena sin formato :
En C ++ haz esto:
En el archivo de texto haga esto:
Por lo tanto, solo debe haber un prefijo en la parte superior del archivo y un sufijo al final del mismo. Entre ellos puedes hacer lo que quieras, no es necesario un escape especial siempre que no necesites la secuencia de caracteres
)"
. Pero incluso esto puede funcionar si especifica su propio delimitador personalizado:fuente
1+R"...
como delimitador inicial en lugar deR"...
, y luego antepone una nueva línea antesLine 1
. Esto transformará la expresión de una matriz a un puntero, pero eso no es realmente un problema aquí, ya que está inicializando un puntero, no una matriz.Tienes dos posibilidades:
\
),"
caracteres de escape y otros para que funcione. Es más fácil escribir un pequeño programa para convertir los bytes en una secuencia como'\xFF', '\xAB', ...., '\0'
(o usar la herramienta Unixxxd
descrita por otra respuesta, si la tiene disponible):Código:
(no probado). Entonces hazlo:
Donde data.h es generado por
fuente
char my_file[] = { #include my_large_file.h };
Gracias!bin2c
no es el mismo bin2c que el de Debianhxtools
, ten cuidadobin2c -H myoutput.h myinput1.txt myinputN.txt
ok, inspirado en la publicación de Daemin probé el siguiente ejemplo simple:
a.data:
prueba.c:
Salida gcc -E test.c:
Por lo tanto, funciona pero requiere datos rodeados de comillas.
fuente
Me gusta la respuesta de kayahr. Sin embargo, si no desea tocar los archivos de entrada y si está usando CMake , puede agregar las secuencias de caracteres delimitador en el archivo. El siguiente código CMake, por ejemplo, copia los archivos de entrada y ajusta su contenido en consecuencia:
Luego incluya en c ++ de esta manera:
fuente
Puedes hacer esto usando
objcopy
:Ahora tiene un archivo objeto que puede vincular a su ejecutable que contiene símbolos para el comienzo, el final y el tamaño del contenido
myfile.txt
.fuente
Necesitas mi
xtr
utilidad pero puedes hacerlo con unbash script
. Este es un guión que llamobin2inc
. El primer parámetro es el nombre del resultadochar[] variable
. El segundo parámetro es el nombre defile
. La salida es Cinclude file
con el contenido del archivo codificado (en minúsculashex
) como el nombre de variable dado. Elchar array
eszero terminated
, y la longitud de los datos se almacena en$variableName_length
PUEDES OBTENER XTR AQUÍ xtr (personaje eXTRapolator) es GPLV3
fuente
Si está dispuesto a recurrir a algunos trucos sucios, puede ser creativo con literales de cadena sin formato y
#include
para ciertos tipos de archivos.Por ejemplo, supongamos que quiero incluir algunos scripts SQL para SQLite en mi proyecto y quiero resaltar la sintaxis, pero no quiero ninguna infraestructura de compilación especial. Puedo tener este archivo
test.sql
que es SQL válido para SQLite donde--
comienza un comentario:Y luego en mi código C ++ puedo tener:
El resultado es:
O para incluir algún código de Python de un archivo
test.py
que sea un script de Python válido (porque#
comienza un comentario en Python ypass
es un no-op):Y luego en el código C ++:
Lo que dará salida:
Debería ser posible jugar trucos similares para varios otros tipos de código que podría incluir como una cadena. Si es una buena idea o no, no estoy seguro. Es una especie de hack limpio pero probablemente no es algo que desearías en un código de producción real. Sin embargo, podría estar bien para un proyecto de hack de fin de semana.
fuente
Reimplementé xxd en python3, arreglando todas las molestias de xxd:
unsigned
en la matriz.Aquí está el script, filtrado por sí mismo, para que pueda ver lo que hace:
pyxxd.c
Uso (esto extrae el script):
fuente
Lo que podría funcionar es si haces algo como:
Por supuesto, tendrá que tener cuidado con lo que realmente está en el archivo , asegurándose de que no haya comillas dobles, que se escapen todos los caracteres apropiados, etc.
Por lo tanto, podría ser más fácil si solo carga el texto de un archivo en tiempo de ejecución o incrusta el texto directamente en el código.
Si aún quisiera el texto en otro archivo, podría tenerlo allí, pero tendría que estar representado allí como una cadena. Usaría el código como arriba pero sin las comillas dobles. Por ejemplo:
file.txt
main.cpp
Entonces, básicamente, tener una cadena de estilo C o C ++ en un archivo de texto que incluya. Haría que el código fuera más ordenado porque no hay una gran cantidad de texto al comienzo del archivo.
fuente
Incluso si se puede hacer en tiempo de compilación (no creo que pueda hacerlo en general), el texto probablemente sea el encabezado preprocesado en lugar de los contenidos de los archivos al pie de la letra. Espero que tengas que cargar el texto del archivo en tiempo de ejecución o hacer un trabajo desagradable de cortar y pegar.
fuente
La respuesta de Hasturkun usando la opción xxd -i es excelente. Si desea incorporar el proceso de conversión (texto -> archivo de inclusión hexadecimal) directamente en su compilación, la herramienta / biblioteca hexdump.c agregó recientemente una capacidad similar a la opción -i de xxd (no le da el encabezado completo; necesita para proporcionar la definición de la matriz de caracteres, pero eso tiene la ventaja de permitirle elegir el nombre de la matriz de caracteres):
http://25thandclement.com/~william/projects/hexdump.c.html
Su licencia es mucho más "estándar" que xxd y es muy liberal: puede ver un ejemplo de su uso para incrustar un archivo init en un programa en los archivos CMakeLists.txt y schema.c aquí:
https://github.com/starseeker/tinyscheme-cmake
Existen ventajas y desventajas para incluir los archivos generados en los árboles de origen y las utilidades de agrupación: cómo manejarlo dependerá de los objetivos y necesidades específicos de su proyecto. hexdump.c abre la opción de agrupación para esta aplicación.
fuente
Creo que no es posible solo con el compilador y el preprocesador. gcc permite esto:
Pero desafortunadamente no esto:
El error es:
fuente
/etc/hostname
como una forma de incrustar el nombre de la máquina de compilación en la cadena, que (incluso si funcionara) no sería portátil ya que Mac OS X no tiene un archivo/etc/hostname
. Tenga en cuenta que usar nombres de macro que comienzan con un guión bajo seguido de una letra mayúscula es usar un nombre reservado para la implementación, que es A Bad Thing ™.¡Por qué no vincular el texto al programa y usarlo como una variable global! Aquí hay un ejemplo. Estoy considerando usar esto para incluir archivos de sombreador Open GL dentro de un ejecutable ya que los sombreadores GL deben compilarse para la GPU en tiempo de ejecución.
fuente
Tuve problemas similares, y para archivos pequeños, la solución antes mencionada de Johannes Schaub funcionó de maravilla para mí.
Sin embargo, para archivos que son un poco más grandes, se encontró con problemas con el límite de matriz de caracteres del compilador. Por lo tanto, escribí una pequeña aplicación de codificador que convierte el contenido del archivo en una matriz de caracteres 2D de fragmentos de igual tamaño (y posiblemente ceros de relleno). Produce archivos de texto de salida con datos de matriz 2D como este:
donde 4 es en realidad una variable MAX_CHARS_PER_ARRAY en el codificador. El archivo con el código C resultante, llamado, por ejemplo, "main_js_file_data.h" se puede insertar fácilmente en la aplicación C ++, por ejemplo, así:
Aquí está el código fuente del codificador:
fuente
Este problema me estaba irritando y xxd no funciona para mi caso de uso porque hizo que la variable se llamara algo así como __home_myname_build_prog_cmakelists_src_autogen cuando intenté escribirlo, así que hice una utilidad para resolver este problema exacto:
https://github.com/Exaeta/brcc
Genera un archivo fuente y de encabezado y le permite establecer explícitamente el nombre de cada variable para que pueda usarlas a través de std :: begin (arrayname) y std :: end (arrayname).
Lo incorporé a mi proyecto cmake así:
Con pequeños ajustes, supongo que también podría funcionar para C.
fuente
en xh
en main.c
Debería hacer el trabajo.
fuente