可能基于预处理器生成的“事物”#if 或#ifdef

发布于 2024-09-17 17:59:47 字数 1683 浏览 1 评论 0原文

我正在尝试进行一些仅 C 预处理器的模板工作,以便对某些代码进行类型专门化。我试图将其简化一点,所以这个例子看起来微不足道且毫无意义,但真正的挑战是获得“包含”阻塞。

假设我有一个“模板”文件,它在包含模板之前从定义 T_ELEMENT_TYPE 的其他源文件中获取#included。

// Template file...
#ifndef T_ELEMENT_TYPE
#error #define T_ELEMENT_TYPE
#endif

#define PASTER(x,y) x ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SYMBOLNAME EVALUATOR(SymbolFor, T_ELEMENT_TYPE)

#ifndef SYMBOLNAMEISDEFINED
#define SYMBOLNAMEISDEFINED EVALUTOR(DEFINEDFOR, T_ELEMENT_TYPE)

int SYMBOLNAME(T_ELEMENT_TYPE arg)
{
    // do something with arg
    return 0;
}

#endif // Guard #ifdef

然后我想包含来自多个实例化站点的模板,但我只希望每个唯一的 T_ELEMENT_TYPE 生成一次模板化函数(以免创建重复的符号。)就像这样说:

// Template-using file...    
#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE float
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

int someOtherFunc()
{
    int foo = 42;
    foo = SymbolForint(foo);
    float bar = 42.0;
    bar = SymbolForfloat(bar);
    return foo;
}

所以我正在寻找我可以的东西在模板代码中使用。我想象它可能看起来像这样(尽管这不起作用):

// Template file...
#ifndef T_ELEMENT_TYPE
#error #define T_ELEMENT_TYPE
#endif

#define PASTER(x,y) x ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SYMBOLNAME EVALUATOR(SymbolFor, T_ELEMENT_TYPE)

#ifndef SYMBOLNAMEISDEFINED
#define SYMBOLNAMEISDEFINED EVALUTOR(DEFINEDFOR, T_ELEMENT_TYPE)

int SYMBOLNAME(T_ELEMENT_TYPE arg)
{
    // do something with arg
    return 0;
}

#endif // Guard #ifdef

这个特定的咒语会阻止模板的所有多个实例化,而不仅仅是针对 T_ELEMENT_TYPE 的不同值。

我可以使用什么技巧来达到这种效果吗?或者可以这么说,我刚刚离开了C预处理器保留吗?

I'm trying to engage in some C-preprocessor-only templating efforts in order to type-specialize some code. I've tried to boil it down a bit, so this example seems trivial and pointless, but the real challenge is getting the "include" blocking.

Say I have a "template" file, that gets #included from other source files that define T_ELEMENT_TYPE before including the template.

// Template file...
#ifndef T_ELEMENT_TYPE
#error #define T_ELEMENT_TYPE
#endif

#define PASTER(x,y) x ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SYMBOLNAME EVALUATOR(SymbolFor, T_ELEMENT_TYPE)

#ifndef SYMBOLNAMEISDEFINED
#define SYMBOLNAMEISDEFINED EVALUTOR(DEFINEDFOR, T_ELEMENT_TYPE)

int SYMBOLNAME(T_ELEMENT_TYPE arg)
{
    // do something with arg
    return 0;
}

#endif // Guard #ifdef

Then I want to include that template from multiple instantiation sites, but I only want the templated function to be generated ONCE per unique T_ELEMENT_TYPE (so as not to create duplicate symbols.) Like, say this:

// Template-using file...    
#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE float
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

int someOtherFunc()
{
    int foo = 42;
    foo = SymbolForint(foo);
    float bar = 42.0;
    bar = SymbolForfloat(bar);
    return foo;
}

So I'm looking for something I can use in the template code. I imagined it might look something like this (although this does not work):

// Template file...
#ifndef T_ELEMENT_TYPE
#error #define T_ELEMENT_TYPE
#endif

#define PASTER(x,y) x ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SYMBOLNAME EVALUATOR(SymbolFor, T_ELEMENT_TYPE)

#ifndef SYMBOLNAMEISDEFINED
#define SYMBOLNAMEISDEFINED EVALUTOR(DEFINEDFOR, T_ELEMENT_TYPE)

int SYMBOLNAME(T_ELEMENT_TYPE arg)
{
    // do something with arg
    return 0;
}

#endif // Guard #ifdef

This particular incantation blocks ALL multiple instantiations of the template, not just for different values of T_ELEMENT_TYPE.

Is there a trick I can use to get this effect? Or am I just off the C-Preprocessor reservation, so to speak?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我的影子我的梦 2024-09-24 17:59:47

我想你已经取消预订了。 #define 的第一个“参数”,即宏名称,不受宏扩展的影响。所以我不认为预处理器可以根据T_ELEMENT_TYPE的值定义不同的符号。预处理器也不能构造一个已经见过的类型的“列表”并检查其中是否存在。

所以我认为 include-guard 必须位于文件之外:

#ifndef included_mytemplatefile_h_int
    #undef T_ELEMENT_TYPE
    #define T_ELEMENT_TYPE int
    #include "mytemplatefile.h"
    #define included_mytemplatefile_h_int
#endif

或者,如果您的模板文件头仅声明函数 SymbolFor_int,而不是定义它,则多重包含不会有害。您可以在文件中不依赖于 T_ELEMENT_TYPE 当前值的部分周围有一个正常的包含保护,包括 PASTER、EVALUATOR、SYMBOLNAME 的定义。您需要一个包含定义的单独模板文件,程序(而不是每个翻译单元)只需要一次:

template_%.c :
    echo "#define T_ELEMENT_TYPE $*" > $@
    echo "#include \"mytemplatedefinitions.c\"" >> $@

然后将 template_int.o 添加到链接到程序的文件列表中。

I think you're off the reservation. The first "argument" to #define, the macro name, isn't subject to macro-expansion. So I don't think the preprocessor can define a different symbol according to the value of T_ELEMENT_TYPE. Neither can the preprocessor construct a "list" of already-seen types and check for existence in that.

So I think the include-guard will have to be outside the file:

#ifndef included_mytemplatefile_h_int
    #undef T_ELEMENT_TYPE
    #define T_ELEMENT_TYPE int
    #include "mytemplatefile.h"
    #define included_mytemplatefile_h_int
#endif

Alternatively, if your template file header only declares the function SymbolFor_int, instead of defining it, then multiple inclusion isn't harmful. You could have a normal include guard around the parts of the file that don't depend on the current value of T_ELEMENT_TYPE, including the definitions of PASTER, EVALUATOR, SYMBOLNAME. You'd need a separate template file containing definitions, which the program (rather than each translation unit) needs to have exactly once:

template_%.c :
    echo "#define T_ELEMENT_TYPE $*" > $@
    echo "#include \"mytemplatedefinitions.c\"" >> $@

Then add template_int.o to the list of files linked into your program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文