从字符串变量参数调用#include宏的函数?

时间:2018-03-28 20:45:48

标签: c++ macros include

是否可以拥有这样的功能:

const char* load(const char* filename_){
    return
    #include filename_
    ;
};

所以你不必硬编码#include文件?

也许有一些宏?

我画了一个空白,伙计们。我无法判断它是否无法实现,或者它是否只是一个奇怪的解决方案。

编辑:

另外,理想的做法是将其作为编译时操作,否则我知道有更标准的方法来读取文件。因此首先考虑#include。

4 个答案:

答案 0 :(得分:1)

这绝对不可能。

原因是 - 正如贾斯汀在评论中所说的那样 - #include在编译时进行评估。

要在运行时包含文件,需要在程序中“完成”编译器。很多脚本语言都支持这样的东西,但C ++是一种编译语言,它的工作方式不同:编译和运行时间是严格分开的。

答案 1 :(得分:1)

  

我无法判断它是不是很可能

我可以。这是不可能的。

filename_字符串的内容直到运行时才确定 - 运行预处理器时内容未知。编译前处理预处理器宏(或根据您的观点编译第一步)。

如果在运行时确定文件名的选择,则还必须在运行时读取该文件(例如使用fstream)。

  

另外,理想的做法是将其作为编译时操作

您可以影响所包含文件选择的最新时间是预处理器运行时。可用于影响文件的是预处理器宏:

#define filename_ "path/to/file"

// ...
return
#include filename_
;

答案 2 :(得分:1)

您不能使用#include做您想做的事。

实现这种功能的C ++方式是:

  1. 找出文件的大小。
  2. 为文件内容分配内存。
  3. 将文件内容读入已分配的内存。
  4. 将文件内容返回给调用函数。
  5. 最好将返回类型更改为std::string,以减轻处理动态分配内存的负担。

    std::string load(const char* filename)
    {
       std::string contents;
    
       // Open the file
       std::ifstream in(filename);
    
       // If there is a problem in opening the file, deal with it.
       if ( !in )
       {
          // Problem. Figure out what to do with it.
       }
    
       // Move to the end of the file.
       in.seekg(0, std::ifstream::end);
    
       auto size = in.tellg();
    
       // Allocate memory for the contents.
       // Add an additional character for the terminating null character.
       contents.resize(size+1);
    
       // Rewind the file.
       in.seekg(0);
    
       // Read the contents
       auto n = in.read(contents.data(), size);
       if ( n != size )
       {
          // Problem. Figure out what to do with it.
       }
    
       contents[size] = '\0';
       return contents;
    };
    

    <强> PS

    仅当您因某种原因需要将返回对象的内容视为空终止字符串时,才需要在返回的对象中使用终止空字符。否则,它可能会被省略。

答案 3 :(得分:1)

理论上可能。

实际上,您要求使用C ++编写PHP构造。这可以做到,因为太多事情可以,你需要一些尴尬的先决条件。

  • 编译器必须链接到您的可执行文件中。因为您调用的操作&#34; hardcoding&#34;对于要执行的代码至关重要。

  • a(可能非常繁琐)链接器再次进入您的可执行文件,合并新代码并解决任何函数调用等双向

此外,新导入的代码可以被的其余部分访问,而没有编写(当然也没有编译!),并记住了这些信息。所以你需要一个切入点和一种交换信息的方法。然后在这个信息块中,您甚至可以将指针指向要调用的代码。

并非所有架构和操作系统都支持此,因为&#34;数据&#34;和#34;代码&#34;两个问题最好分开。守则可能有害;把它想象成硝酸。外部数据是流动和光滑的,如甘油。正如我所说,处理硝酸甘油是可能的。实用和安全是完全不同的。

满足先决条件后,您将拥有两个或三个不错的额外功能,并且可以写:

void *load(const char* filename, void *data) {
    // some "don't load twice" functionality is probably needed
    void *code = compile_source(filename);
    if (NULL == code) {
        // a get_last_compiler_error() would be useful
        return NULL;
    }
    if (EXIT_SUCCESS != invoke_code(code, data)) {
        // a get_last_runtime_error() would also be useful
        release_code(code);
        return NULL;
    }
    // it is now the caller's responsibility to release the code.
    return code;
}

当然这将是一场安全噩梦,其中包含源代码并被导入到正在运行的应用程序中。

维护代码将是一个不同但同样可怕的噩梦,因为您需要两个工具链 - 一个用于构建可执行文件,一个嵌入在所述可执行文件中 - 并且他们不会&# 39;必须自动兼容。你会大声哭泣,因为这个领域的所有错误都要来欢欣鼓舞。

将解决什么问题?

在C ++中实现require_once可能很有趣,但you thought it could answer a problem you have它究竟是什么?也许它可以用更多的C ++方式解决。

更好的替代方案,也考虑到性能等,预先编译可加载模块,并在运行时加载它。

如果需要对可执行文件执行小调整,请将参数放入外部配置文件并提供重新加载它的机制。一旦模块符合固定规范,您甚至可以提供&#34;插件&#34;首次开发可执行文件时无法使用。