有没有办法在C预处理器中执行任意代码?

时间:2019-02-05 18:57:41

标签: c gcc lisp

考虑此程序:

#define MACRO                                   \
    srand(time(NULL));                          \
    if (rand() % 2)                             \
        printf("A");                            \
    else                                        \
        printf("B");

int main() {
    MACRO;
}

它等效于以下宏扩展程序:

int main() {
    srand(time(NULL));
    if (rand() % 2)
        printf("A");
    else
        printf("B");
}

很显然,if语句是在运行时而不是在宏扩展阶段执行的。如果if语句是在编译时执行的,并且有语法引用(如Lisp),则我们可以(几乎)相等的概率获得程序A和A'。其中A:

int main() {
    printf("A");
}

和A':

int main() {
    printf("B");
}

就编译时评估的条件而言,有没有办法让GCC发出A或A'?

3 个答案:

答案 0 :(得分:3)

  

有没有办法在C预处理器中执行任意代码?

否,这是原始(1989)C标准作者的故意设计决定。他们熟悉功能更强大的宏系统(例如,来自Lisp的宏系统,它确实允许在编译时进行任意计算),并且认为这些使理解一个陌生程序意味着什么变得太难了。

我不清楚您为什么要在编译时进行随机选择。如果您解释了更大的目标,我们可能会有所帮助。

答案 1 :(得分:1)

您无法在预处理器中执行代码。但是,您可以创建用于生成代码的代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() 
{
    printf("#include <stdio.h>\n");
    printf("\n");
    printf("int main()\n");
    printf("{\n");

    srand(time(NULL));
    if (rand() % 2)
        printf("  printf(\"A\");\n");
    else
        printf("  printf(\"B\");\n");

    printf("}\n");
}

输出:

#include <stdio.h>

int main()
{
  printf("A");
}

或者:

#include <stdio.h>

int main()
{
  printf("B");
}

答案 2 :(得分:0)

要基于模数乘以随机数二的结果进行编译,我们需要使用BoostPP

#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>

BOOST_PP_IF(BOOST_PP_MOD(RAND, 2), printf("A"); printf("B");)

您将需要使用-D选项进行编译以从RAND分配给/dev/random,就像在注释中建议的那样。

以下是条件宏的一些实现细节,以带您了解其工作原理。模运算需要实现数据类型及其上的运算,在这里无法证明。

#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,

#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 PROBE(~)

#define BOOL(x) COMPL(NOT(x))

#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

#define IF(c) IIF(BOOL(c))

#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)

以及用法。请注意,WHEN(0)不会展开,其他任何WHEN(arg)都会展开。

WHEN(0) ( \
  printf("A"); \
)
WHEN(1) ( \
  printf("B"); \
)
WHEN(whatever) ( \
  printf("this will expand too"); \
)

查看a concise intro to high level CPPsource for the macros in this example,以获取有关上面的宏的更多详细信息。