سؤال

هل هناك طريقة إدراج ملف النص بأكمله كسلسلة في برنامج C في تجميع الوقت ؟

شيء من هذا القبيل:

  • file.txt:

    This is
    a little
    text file
    
  • الرئيسية.ج:

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

الحصول على برنامج صغير يطبع على stdout "هذا هو قليلا ملف نصي"

في هذه اللحظة أنا استخدمت hackish بيثون السيناريو, لكنه قبيحة و تقتصر على واحد فقط اسم المتغير, هل يمكن أن تخبرني طريقة أخرى للقيام بذلك ؟

هل كانت مفيدة؟

المحلول

أقترح استخدام (unix util)xxd من أجل هذا.يمكنك استخدامه مثل ذلك

$ echo hello world > a
$ xxd -i a

النواتج:

unsigned char a[] = {
  0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;

نصائح أخرى

كان السؤال عن " ج " ولكن في حال حاول شخص ما أن تفعل ذلك مع C++11 ثم يمكن أن يتم ذلك فقط مع القليل من التغييرات شملت ملف نصي شكرا الجديد الخام سلسلة حرفية:

في C++ القيام بذلك:

const char *s =
#include "test.txt"
;

في ملف نصي القيام بذلك:

R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"

لذلك يجب أن يكون هناك فقط تكون البادئة في الجزء العلوي من ملف لاحقة في نهاية الأمر.بين أنه يمكنك أن تفعل ما تريد, لا مفر من الضروري طالما أنت لا تحتاج إلى تسلسل الأحرف )".ولكن حتى هذا يمكن أن تعمل إذا كان يمكنك تحديد الخاصة بك مخصص محدد:

R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="

لديك احتمالين:

  1. الاستفادة من برنامج التحويل البرمجي/رابط يتم تحويل الملف إلى ملف ثنائي مع المناسبة رموز تشير إلى begin و end من البيانات الثنائية.انظر هذا الجواب: تشمل ملف ثنائي مع جنو ld رابط نصي.
  2. تحويل الملف إلى سلسلة من حرف الثوابت التي يمكن تهيئة صفيف.ملاحظة لا يمكنك فقط أن تفعل "" وتمتد خطوط متعددة.كنت في حاجة الى خط حرف متابعة (\), الهروب " شخصيات الآخرين لجعل هذا العمل.من الأسهل أن مجرد كتابة برنامج صغير لتحويل بايت في تسلسل مثل '\xFF', '\xAB', ...., '\0' (أو استخدام أداة unix xxd وصفها إجابة أخرى, إذا كان لديك المتاحة!):

كود:

#include <stdio.h>

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

(لم تختبر).ثم القيام:

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

حيث البيانات.ح يتم إنشاؤها من قبل

cat file.bin | ./bin2c > data.h

حسنا, مستوحاة من Daemin هو بعد اختبرت البسيطة التالية على سبيل المثال :

أ.البيانات:

"this is test\n file\n"

الاختبار.ج:

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

دول مجلس التعاون الخليجي -E الاختبار.ج الإخراج:

# 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;
}

حتى انها تعمل ولكن تتطلب البيانات محاطة بعلامات اقتباس.

أنا أحب kayahr الجواب. إذا كنت لا تريد أن تلمس ملفات الإدخال ومع ذلك ، إذا كنت تستخدم CMake, يمكنك إضافة delimeter تسلسل الأحرف على الملف.التالية CMake رمز, على سبيل المثال, نسخ ملفات الإدخال و يلتف مضمونها وفقا لذلك:

function(make_includable input_file output_file)
    file(READ ${input_file} content)
    set(delim "for_c++_include")
    set(content "R\"${delim}(\n${content})${delim}\"")
    file(WRITE ${output_file} "${content}")
endfunction(make_includable)

# Use like
make_includable(external/shaders/cool.frag generated/cool.frag)

ثم تدرج في c++ مثل هذا:

constexpr char *test =
#include "generated/cool.frag"
;

ما قد عمل هو إذا كنت تفعل شيئا مثل:

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

بالطبع عليك أن تكون حذرا مع ما هو في الواقع في الملف ، مع التأكد من أن هناك أي علامات الاقتباس المزدوجة ، أن جميع الأحرف المناسبة هي هرب ، إلخ.

ولذلك قد يكون أسهل إذا كنت فقط تحميل النص من ملف في وقت التشغيل ، أو تضمين النص مباشرة في التعليمات البرمجية.

إذا كنت لا تزال تريد النص في ملف آخر هل يمكن أن يكون هناك ، ولكن يجب أن تكون ممثلة هناك كسلسلة.يمكنك استخدام التعليمات البرمجية أعلاه ولكن دون التنصيص في ذلك.على سبيل المثال:

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

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

كنت بحاجة لي xtr فائدة ولكن يمكنك أن تفعل ذلك مع bash script.هذا هو السيناريو أسميه bin2inc.المعلمة الأولى هو اسم الناتجة char[] variable.المعلمة الثانية هي اسم file.الإخراج هو ج include file مع محتوى الملف المشفر (في صغيرة hex) مثل اسم متغير معين.على char array هو zero terminated, و طول يتم تخزين البيانات في $variableName_length

#!/bin/bash

fileSize ()

{

    [ -e "$1" ]  && {

        set -- `ls -l "$1"`;

        echo $5;

    }

}

echo unsigned char $1'[] = {'
./xtr -fhex -p 0x -s ', ' < "$2";
echo '0x00'
echo '};';
echo '';
echo unsigned long int ${1}_length = $(fileSize "$2")';'

يمكنك الحصول على XTR هنا xtr (حرف eXTRapolator) هو GPLV3

يمكنك القيام بذلك باستخدام objcopy:

objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o

الآن لديك كائن الملف يمكنك ربط إلى جهاز قابل للتنفيذ الذي يحتوي على رموز بداية, نهاية, و حجم المحتوى من myfile.txt.

أنا ل reimplemented xxd في python3 ، وتحديد كل من xxd هناك مضايقات:

  • Const صحة
  • طول سلسلة نوع البيانات:الباحث → size_t
  • Null إنهاء الخدمة (في حال كنت قد ترغب في ذلك)
  • C سلسلة متوافق:قطرة unsigned في الصفيف.
  • أصغر للقراءة الانتاج, كما كنت قد كتبت:للطباعة ascii هو الإخراج كما هو ؛ أخرى بايت عرافة المشفرة.

هنا هو السيناريو التي تمت تصفيتها من قبل نفسه ، حتى تتمكن من رؤية ما يفعله:

pyxxd.ج

#include <stddef.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

const char pyxxd[] =
"#!/usr/bin/env python3\n"
"\n"
"import sys\n"
"import re\n"
"\n"
"def is_printable_ascii(byte):\n"
"    return byte >= ord(' ') and byte <= ord('~')\n"
"\n"
"def needs_escaping(byte):\n"
"    return byte == ord('\\\"') or byte == ord('\\\\')\n"
"\n"
"def stringify_nibble(nibble):\n"
"    if nibble < 10:\n"
"        return chr(nibble + ord('0'))\n"
"    return chr(nibble - 10 + ord('a'))\n"
"\n"
"def write_byte(of, byte):\n"
"    if is_printable_ascii(byte):\n"
"        if needs_escaping(byte):\n"
"            of.write('\\\\')\n"
"        of.write(chr(byte))\n"
"    elif byte == ord('\\n'):\n"
"        of.write('\\\\n\"\\n\"')\n"
"    else:\n"
"        of.write('\\\\x')\n"
"        of.write(stringify_nibble(byte >> 4))\n"
"        of.write(stringify_nibble(byte & 0xf))\n"
"\n"
"def mk_valid_identifier(s):\n"
"    s = re.sub('^[^_a-z]', '_', s)\n"
"    s = re.sub('[^_a-z0-9]', '_', s)\n"
"    return s\n"
"\n"
"def main():\n"
"    # `xxd -i` compatibility\n"
"    if len(sys.argv) != 4 or sys.argv[1] != \"-i\":\n"
"        print(\"Usage: xxd -i infile outfile\")\n"
"        exit(2)\n"
"\n"
"    with open(sys.argv[2], \"rb\") as infile:\n"
"        with open(sys.argv[3], \"w\") as outfile:\n"
"\n"
"            identifier = mk_valid_identifier(sys.argv[2]);\n"
"            outfile.write('#include <stddef.h>\\n\\n');\n"
"            outfile.write('extern const char {}[];\\n'.format(identifier));\n"
"            outfile.write('extern const size_t {}_len;\\n\\n'.format(identifier));\n"
"            outfile.write('const char {}[] =\\n\"'.format(identifier));\n"
"\n"
"            while True:\n"
"                byte = infile.read(1)\n"
"                if byte == b\"\":\n"
"                    break\n"
"                write_byte(outfile, ord(byte))\n"
"\n"
"            outfile.write('\";\\n\\n');\n"
"            outfile.write('const size_t {}_len = sizeof({}) - 1;\\n'.format(identifier, identifier));\n"
"\n"
"if __name__ == '__main__':\n"
"    main()\n"
"";

const size_t pyxxd_len = sizeof(pyxxd) - 1;

استخدام (هذه مقتطفات النص):

#include <stdio.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

int main()
{
    fwrite(pyxxd, 1, pyxxd_len, stdout);
}

حتى إذا كان يمكن القيام به في وقت الترجمة (أنا لا أعتقد أنه يمكن في العامة) النص من المرجح أن تكون معالجة رأس بدلا من ملفات المحتويات الحرفية.أتوقع سيكون لديك لتحميل النص من ملف في وقت التشغيل أو جرح-n-لصق الوظيفي.

في العاشر.ح

"this is a "
"buncha text"

في الرئيسية.ج

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

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

    return 0
}

يجب القيام بهذه المهمة.

Hasturkun رد باستخدام xxd -لا خيار ممتاز.إذا كنت ترغب في إدراج عملية التحويل (النص -> عرافة تشمل الملف) مباشرة في بناء hexdump.ج أداة/مكتبة مؤخرا بإضافة القدرة على غرار xxd هذا الخيار-i (لا تعطيك كامل رأس - تحتاج إلى توفير شار مجموعة التعريف - ولكن لديها ميزة السماح لك اختيار اسم char array):

http://25thandclement.com/~william/projects/hexdump.c.html

انها رخصة الكثير من "المعيار" من xxd جدا الليبرالية - مثال على استخدامه إلى تضمين الحرف الأول الملف في البرنامج يمكن أن ينظر إليه في CMakeLists.txt ومخطط.ج الملفات من هنا:

https://github.com/starseeker/tinyscheme-cmake

هناك إيجابيات وسلبيات على حد سواء بما في ذلك الملفات التي تم إنشاؤها في المصدر الأشجار و تجميع المرافق - كيفية التعامل معها يعتمد على أهداف محددة و احتياجات المشروع الخاص بك.hexdump.ج يفتح تجميع الخيار لهذا التطبيق.

أعتقد أنه ليس من الممكن مع مترجم و المعالج وحده.دول مجلس التعاون الخليجي يسمح هذا:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               define hostname my_dear_hostname
                hostname
            )
            "\n" );

ولكن للأسف ليس هذا:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               include "/etc/hostname"
            )
            "\n" );

الخطأ هو:

/etc/hostname: In function ‘init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"

لماذا لا وصلة النص إلى البرنامج واستخدامه عالمي متغير! هنا هو مثال على ذلك. أنا تفكر في استخدام هذا أن تشمل فتح GL تظليل الملفات داخل ملف قابل للتنفيذ منذ GL تظليل تحتاج إلى أن تكون جمعت GPU في وقت التشغيل.

لدي قضايا مماثلة ، ملفات صغيرة المذكور حل يوهانس شواب تعمل مثل السحر بالنسبة لي.

ومع ذلك ، عن الملفات التي هي أكبر قليلا ، واجهت مشاكل مع صفيف حرف حد برنامج التحويل البرمجي.ولذلك كتبت صغيرة التشفير التطبيق الذي يحول محتوى الملف في شخصية 2D مجموعة من قطع متساوية الحجم (وربما الحشو أصفار).وتنتج انتاج textfiles مع 2D مجموعة بيانات من هذا القبيل:

const char main_js_file_data[8][4]= {
    {'\x69','\x73','\x20','\0'},
    {'\x69','\x73','\x20','\0'},
    {'\x61','\x20','\x74','\0'},
    {'\x65','\x73','\x74','\0'},
    {'\x20','\x66','\x6f','\0'},
    {'\x72','\x20','\x79','\0'},
    {'\x6f','\x75','\xd','\0'},
    {'\xa','\0','\0','\0'}};

حيث 4 هو في الواقع متغير MAX_CHARS_PER_ARRAY في التشفير.الملف الناتج كما يسمى ، على سبيل المثال "main_js_file_data.ح" ثم يمكنك بسهولة المضمنة في C++ التطبيق ، على سبيل المثال مثل هذا:

#include "main_js_file_data.h"

هنا هو رمز مصدر من التشفير:

#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>


#define MAX_CHARS_PER_ARRAY 2048


int main(int argc, char * argv[])
{
    // three parameters: input filename, output filename, variable name
    if (argc < 4)
    {
        return 1;
    }

    // buffer data, packaged into chunks
    std::vector<char> bufferedData;

    // open input file, in binary mode
    {    
        std::ifstream fStr(argv[1], std::ios::binary);
        if (!fStr.is_open())
        {
            return 1;
        }

        bufferedData.assign(std::istreambuf_iterator<char>(fStr), 
                            std::istreambuf_iterator<char>()     );
    }

    // write output text file, containing a variable declaration,
    // which will be a fixed-size two-dimensional plain array
    {
        std::ofstream fStr(argv[2]);
        if (!fStr.is_open())
        {
            return 1;
        }
        const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
        fStr << "const char " << argv[3] << "[" << numChunks           << "]"    <<
                                            "[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
        std::size_t count = 0;
        fStr << std::hex;
        while (count < bufferedData.size())
        {
            std::size_t n = 0;
            fStr << "{";
            for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
            {
                fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
            }
            // fill missing part to reach fixed chunk size with zero entries
            for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
            {
                fStr << "'\\0',";
            }
            fStr << "'\\0'}";
            if (count < bufferedData.size())
            {
                fStr << ",\n";
            }
        }
        fStr << "};\n";
    }

    return 0;
}

إذا كنت على استعداد اللجوء إلى بعض الحيل القذرة يمكنك الحصول على خلاقة مع الخام سلسلة حرفية ، #include على أنواع معينة من الملفات.

على سبيل المثال ، يقول أريد أن تدرج بعض البرامج النصية SQL على SQLite في المشروع و أريد الحصول على تسليط الضوء على بناء الجملة ولكن لا أريد أي بناء البنية التحتية.أنا يمكن أن يكون هذا الملف test.sql وهو SQL صالح عن سكليتي حيث -- يبدأ التعليق:

--x, R"(--
SELECT * from TestTable
WHERE field = 5
--)"

ثم في C++ كود أنا يمكن أن يكون:

int main()
{
    auto x = 0;
    const char* mysql = (
#include "test.sql"
    );

    cout << mysql << endl;
}

الناتج هو:

--
SELECT * from TestTable
WHERE field = 5
--

أو أن تدرج بعض الثعبان رمز من الملف test.py وهو صالح بيثون السيناريو (لأن # يبدأ التعليق في بيثون ، pass لا-op):

#define pass R"(
pass
def myfunc():
    print("Some Python code")

myfunc()
#undef pass
#define pass )"
pass

ثم في C++ code:

int main()
{
    const char* mypython = (
#include "test.py"
    );

    cout << mypython << endl;
}

والتي سوف الإخراج:

pass
def myfunc():
    print("Some Python code")

myfunc()
#undef pass
#define pass

وينبغي أن يكون من الممكن أن تلعب الحيل مماثلة لمختلف أنواع أخرى من التعليمات البرمجية قد ترغب في تضمين كسلسلة.ما إذا كان أو لم يكن هو فكرة جيدة أنا لست متأكدا.انها نوع من الإختراق أنيق ولكن ربما ليست شيئا كنت تريد في الإنتاج الحقيقي التعليمات البرمجية.قد يكون حسنا في عطلة نهاية الأسبوع هاك المشروع على الرغم من.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top