【问题标题】:How to store data inside the executable file如何在可执行文件中存储数据
【发布时间】:2011-02-06 18:32:47
【问题描述】:

我需要找到一种方法在我的程序的可执行文件中存储 250 KB 的纯文本数字。

通常,我会将数据放在一个单独的文件中,让程序在运行时读取它,但这不是这里的选择。相反,程序和数据需要在一个可执行文件中。

我完全不知道该怎么做(除了写 250.000 #defines :-),如果有任何建议,我将不胜感激。

【问题讨论】:

  • 什么平台?例如,你能使用 Win32 资源吗?
  • 类似问题(无耻塞):stackoverflow.com/questions/2481998/…
  • 对于那些建议使用数组的人,我也想过这个问题,但因编译时间长而气馁。猜想毕竟是对的。谢谢!
  • 只需将您的数组放在它自己的源文件中,如果您使用的是健全的构建系统,您应该只需要编译一次(直到您进行完全重建)。
  • 如何在不硬编码的情况下将数据存储在可执行文件中?我要存储的数据是用户输入的。

标签: c storage executable


【解决方案1】:

某种数组怎么样。只需将该定义放在一个文件中并将其编译到您的程序中即可:

int external_data[] =
{
    ...
};

您可以让编译器告诉您外部数据中有多少元素:

size_t external_data_max_idx = sizeof(external_data) / sizeof(*external_data);

【讨论】:

  • +1 用于在单独的文件中建议定义。我目前正在使用这种技术,我只需要更改文件并重新构建,尤其是在数据更改时。
【解决方案2】:

您可以只生成一个数组定义。例如,假设你有numbers.txt:

$ head -5 numbers.txt
0.99043748698114
0.0243802034269436
0.887296518349228
0.0644020236531517
0.474582201929554

我已经为示例生成了它,使用:

$ perl -E'say rand() for (1..250_000)' >numbers.txt

然后要将其转换为 C 数组定义,您可以使用脚本:

$ perl -lpE'BEGIN{ say "double data[] = {"; }; 
>     END{ say "};" }; 
>     s/$/,/' > data.h < numbers.txt 

它产生:

$ head -5 data.h
double data[] = {
0.99043748698114,
0.0243802034269436,
0.887296518349228,
0.0644020236531517,

$ tail -5 data.h
0.697015237317363,
0.642250552146166,
0.00577098769553785,
0.249176256744811,
};

它可以在你的程序中使用如下:

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

int main(void) {
  // print first and last numbers
  printf("%g %g\n", data[0], data[sizeof(data)/sizeof(*data)-1]);
  return 0;
}

运行它:

$ gcc *.c && ./a.out
0.990437 0.249176

【讨论】:

    【解决方案3】:

    将其存储为 const 数组:

    /* Maximum number of digits in a number, adjust as necessary */
    #define NUMBER_MAX_LENGTH 16
    
    /* How many numbers you have (in this case 250K), adjust as necessary */
    #define NUMBER_OF_NUMBERS (250 * (1 << 10))
    
    const char data[NUMBER_OF_NUMBERS][NUMBER_MAX_LENGTH+1] =
     { "12345", "2342841", "129131", "18317", /* etc */ };
    

    大概您知道您的数据集,因此您可以根据您的情况为NUMBER_MAX_LENGTH 提出适当的值。

    当然,您也可以编写一个脚本,将数字的平面文件转换为这种格式。如果需要,您甚至可以将数字保存在纯文本数据文件中,并让脚本在构建过程中生成上述相应的 C 代码。

    我这样写是因为您说“纯文本数字”,表明您出于某种原因需要将它们作为字符串。如果您希望将它们作为整数,则更简单:

    /* How many numbers you have (in this case 250K), adjust as necessary */
    #define NUMBER_OF_NUMBERS (250 * (1 << 10))
    
    const int data[NUMBER_OF_NUMBERS] =
     { 12345, 2342841, 129131, 18317, /* etc */ };
    

    假设您的数字都不是太大而无法存储在 int 中。

    【讨论】:

    • 您可以只使用data[] 而不是使用数字宏。
    【解决方案4】:

    您可以使用带有-i 选项的xxd 命令将任何文件转换为C 中的字符向量。如果你在 Windows 上,你可以考虑在 Cygwin 中使用它。

    【讨论】:

      【解决方案5】:

      假设数字是常数。让我们假设,您可以在“预编译”阶段计算此列表一次。让我们假设有一个函数可以“返回”该列表。

      第一阶段: 编写一个调用 getFooNumber() 并完美运行的应用程序。不错。

      第二阶段: 获取该功能,并将其放入另一个项目中。现在,让我们编写一个将生成 250,000 行 C 代码的小应用程序。

      #include <stdlib>
      #define MAX_BLABLA 2500000
      
      int main(int argc, char *argv[] )
      {
        FILE *f fopen("fooLookupTable.h");
        long i;
        fprintf( f, "#ifndef FOO_HEADER\n");
        fprintf( f, "#define FOO_HEADER\n");
      
        fprintf( f, "char [] blabla = {\n\t");
        for( i=0; i<MAX_BLABLA; i ++ )
        {
           fprintf(f, "%d", getFooNumber(i) );
           if (n+1 != MAX_BLABLA)
               fprintf(f, ",");
           if (n%10 == 0)
               fprintf(f, "\n\t");
        }
        fprintf( f, "};\n\n");
        fprintf( f, "#endif // FOO_HEADER\n");
      }
      

      这将创建比利·奥尼尔谈到的列表。

      第 3 阶段: 使用您刚刚在第 2 阶段创建的头文件,并在第一个项目中使用它从新的 getFooNumber() 返回查找表中的值。

      第 4 阶段: 学习使用Qt,了解可以直接嵌入文件,使用QFile(":application/numberz.txt")加载。

      注意事项: * C 代码可能已损坏。我没有测试它。 * 如果你使用的是Windows或Mac,你可能可以对资源系统做类似的事情(MAC有类似的事情吗?)

      【讨论】:

      • +1 ,创建一个从数据生成C代码的小程序非常方便。
      【解决方案6】:

      我同意前面的答案。最好的方法是简单地将其存储在代码中,然后将其编译到程序中。 为了争论,您可以查看可执行文件的格式并在其中添加一些数据/代码(这是很多病毒的工作方式),然后简单地从可执行文件中读取并获取数据。 http://refspecs.freestandards.org/elf/elf.pdf 具有可执行文件的格式。 再次强调这是为了争论,不推荐。

      【讨论】:

        【解决方案7】:

        听起来您试图避免将其放入源文件中,但这正是我要做的:

        int numbers[250000] = {1, 2, ...};
        

        技术上可以将它们保存为一个普通文件并编写一个链接器指令文件,该文件创建一个适当大小的新数据段并将它们组合起来,但实际上没有理由。将该定义放在一个单独的文件中,并将其#include 到需要它的文件中

        【讨论】:

        • 请注意,您可以只使用“numbers[]`,编译器会为您计算。
        • 是的,但是如果我知道数组中应该包含多少东西,我喜欢包含它,这样查看它的人就会立即知道它的大小,所以如果我搞砸并忘记/复制一个我会得到一个编译时错误
        【解决方案8】:

        您可以将this solution 调整为数字:

        static const wchar_t *systemList[] = {
            L"actskin4.ocx",
            L"advpack.dll",
            L"asuninst.exe",
            L"aswBoot.exe",
            L"AvastSS.scr",
            L"avsda.dll",
            L"bassmod.dll",
            L"browseui.dll",
            L"CanonIJ Uninstaller Information",
            L"capicom.dll",
            L"cdfview.dll",
            L"cdm.dll",
            L"d3dx9_24.dll",
            L"d3dx9_25.dll",
            L"d3dx9_27.dll",
            L"d3dx9_28.dll",
            L"d3dx9_29.dll",
            L"d3dx9_30.dll",
            L"danim.dll",
            L"dfrgntfs.exe",
            L"dhcpcsvc.dll",
            L"dllhost.exe",
            L"dnsapi.dll",
            L"drivers\\aavmker4.sys",
            L"drivers\\apt.sys",
            L"drivers\\aswFsBlk.sys",
            L"drivers\\aswmon.sys",
            L"drivers\\aswmon2.sys",
            L"drivers\\aswRdr.sys",
            L"drivers\\aswSP.sys",
            L"drivers\\aswTdi.sys",
            L"drivers\\avg7core.sys",
            L"drivers\\avg7rsw.sys",
            L"drivers\\avg7rsxp.sys",
            L"drivers\\avgclean.sys",
            L"drivers\\avgmfx86.sys",
            L"drivers\\avgntdd.sys",
            L"drivers\\avgntmgr.sys",
            L"drivers\\avgtdi.sys",
            L"drivers\\avipbb.sys",
            L"drivers\\cmdmon.sys",
            L"drivers\\gmer.sys",
            L"drivers\\inspect.sys",
            L"drivers\\klick.sys",
            L"drivers\\klif.sys",
            L"drivers\\klin.sys",
            L"drivers\\pxcom.sys",
            L"drivers\\pxemu.sys",
            L"drivers\\pxfsf.sys",
            L"drivers\\pxrd.sys",
            L"drivers\\pxscrmbl.sys",
            L"drivers\\pxtdi.sys",
            L"drivers\\rrspy.sys",
            L"drivers\\rrspy64.sys",
            L"drivers\\ssmdrv.sys",
            L"drivers\\UMDF",
            L"drivers\\USBSTOR.SYS",
            L"DRVSTORE",
            L"dxtmsft.dll",
            L"dxtrans.dll",
            L"en-us",
            L"extmgr.dll",
            L"fntcache.dat",
            L"hal.dll",
            L"icardie.dll",
            L"ie4uinit.exe",
            L"ieakeng.dll",
            L"ieaksie.dll",
            L"ieakui.dll",
            L"ieapfltr.dat",
            L"ieapfltr.dll",
            L"iedkcs32.dll",
            L"ieframe.dll",
            L"iepeers.dll",
            L"iernonce.dll",
            L"iertutil.dll",
            L"ieudinit.exe",
            L"ieui.dll",
            L"imon1.dat",
            L"inseng.dll",
            L"iphlpapi.dll",
            L"java.exe",
            L"javaw.exe",
            L"javaws.exe",
            L"jgdw400.dll",
            L"jgpl400.dll",
            L"jscript.dll",
            L"jsproxy.dll",
            L"kbdaze.dll",
            L"kbdblr.dll",
            L"kbdbu.dll",
            L"kbdkaz.dll",
            L"kbdru.dll",
            L"kbdru1.dll",
            L"kbdtat.dll",
            L"kbdur.dll",
            L"kbduzb.dll",
            L"kbdycc.dll",
            L"kernel32.dll",
            L"legitcheckcontrol.dll",
            L"libeay32_0.9.6l.dll",
            L"Macromed",
            L"mapi32.dll",
            L"mrt.exe",
            L"msfeeds.dll",
            L"msfeedsbs.dll",
            L"msfeedssync.exe",
            L"msftedit.dll",
            L"mshtml.dll",
            L"mshtmled.dll",
            L"msrating.dll",
            L"mstime.dll",
            L"netapi32.dll",
            L"occache.dll",
            L"perfc009.dat",
            L"perfh009.dat",
            L"pncrt.dll",
            L"pndx5016.dll",
            L"pndx5032.dll",
            L"pngfilt.dll",
            L"px.dll",
            L"pxcpya64.exe",
            L"pxdrv.dll",
            L"pxhpinst.exe",
            L"pxinsa64.exe",
            L"pxinst.dll",
            L"pxmas.dll",
            L"pxsfs.dll",
            L"pxwave.dll",
            L"rasadhlp.dll",
            L"rasmans.dll",
            L"riched20.dll",
            L"rmoc3260.dll",
            L"rrsec.dll",
            L"rrsec2k.exe",
            L"shdocvw.dll",
            L"shell32.dll",
            L"shlwapi.dll",
            L"shsvcs.dll",
            L"sp2res.dll",
            L"spmsg.dll",
            L"ssiefr.EXE",
            L"STKIT432.DLL",
            L"streamhlp.dll",
            L"SWSC.exe",
            L"tzchange.exe",
            L"url.dll",
            L"urlmon.dll",
            L"vsdata.dll",
            L"vsdatant.sys",
            L"vsinit.dll",
            L"vsmonapi.dll",
            L"vspubapi.dll",
            L"vsregexp.dll",
            L"vsutil.dll",
            L"vswmi.dll",
            L"vsxml.dll",
            L"vxblock.dll",
            L"webcheck.dll",
            L"WgaLogon.dll",
            L"wgatray.exe",
            L"wiaservc.dll",
            L"windowspowershell",
            L"winfxdocobj.exe",
            L"wmp.dll",
            L"wmvcore.dll",
            L"WREGS.EXE",
            L"WRLogonNtf.dll",
            L"wrlzma.dll",
            L"wuapi.dll",
            L"wuauclt.exe",
            L"wuaueng.dll",
            L"wucltui.dll",
            L"wups.dll",
            L"wups2.dll",
            L"wuweb.dll",
            L"x3daudio1_0.dll",
            L"xactengine2_0.dll",
            L"xactengine2_1.dll",
            L"xactengine2_2.dll",
            L"xinput1_1.dll",
            L"xinput9_1_0.dll",
            L"xmllite.dll",
            L"xpsp3res.dll",
            L"zlcomm.dll",
            L"zlcommdb.dll",
            L"ZPORT4AS.dll"
        };
        

        【讨论】:

          【解决方案9】:

          您在哪个平台上运行?如果您在 Windows 上并且数字不会及时更改,那么只需使用资源链接器将您的文本文件放入程序资源中,然后在您的代码中读取它。

          【讨论】:

            【解决方案10】:

            不是解决方案(这是之前给出的)但是:不要把它放在头文件中。编写一个头文件,它定义了一个返回数组的函数。然后在 .c 文件中实现它。否则,你最终会陷入编译混乱......

            【讨论】:

              【解决方案11】:

              只需在可执行程序中创建一个包含任意多个字符的字符串,然后让程序的另一部分将其自身作为文件打开,获取字节,找到已编译的字符串并根据需要直接更改它(make确保在其中放置一个唯一的字符串以使用二进制字符串定位实际区域),可能需要在执行另一个程序后关闭程序,该程序将数据写入原始程序并重新执行它,当原始程序是重新执行它可以从在它的二进制文件中声明的字符串中读取新的写入值,并使用它来执行任何任务。

              【讨论】:

                猜你喜欢
                • 2020-07-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-04-09
                • 2019-06-21
                • 2018-02-23
                • 2018-02-09
                • 1970-01-01
                相关资源
                最近更新 更多