带有三元运算符的宏 - 我可以在运行时通过变量漏斗吗?

macro with ternary operator - can I funnel through variable at runtime?

我想知道是否可以通过预处理器宏汇集非静态变量。 想象一下,我必须调用一个带有 4 个参数的函数,例如 foo(A,B,C,D); 我的输入是 bar,它是一个介于 1 和 4 之间的整数值,而 baz 可以是运行时的任何整数值,如果 'bar' == 1,则进入 A,如果是,则进入 B' == 2 ... D 如果它是 == 4。 我想出了一个看起来像这样的宏:

#define setACports(p,v) ((p) == 4 ? ", , ,(v),"  : \
                        ((p) == 3 ? ", ,(v), ,"  : \
                        ((p) == 2 ? ",(v), , ,"  : \
                       (((p) == 1 ? "(v), , , ," : "invalid")))))

/*example application */
void foo(int var1,int var2,int var3, int var4);                           
int main (void) {
    int i = 0;
    for (i=0;i<5;i++) 
        foo(setACports(i,i));
}

现在,虽然参数 "positioning" 工作正常,但值显然不能正常工作,因为 (v) 在预处理器时不可用。我将如何最好地实施这样的事情?我很困惑什么可能是最好的解决方案,任何建议或提示都会很棒!

对于这个特定示例,由于您正在打印,因此可以将 v 替换为 %d 并将参数附加到末尾。

#define setACports(p,v) ((p) == 4 ? ", , ,(%d),"  : \
                        ((p) == 3 ? ", ,(%d), ,"  : \
                        ((p) == 2 ? ",(%d), , ,"  : \
                       (((p) == 1 ? "(%d), , , ," : "invalid"))))), (v)

输出:

invalid(1), , , ,,(2), , ,, ,(3), ,, , ,(4),

可以做:

#include <stdio.h>

#define setACports(p, v) \
  (p) == 1 ?(v) :0, \
  (p) == 2 ?(v) :0, \
  (p) == 3 ?(v) :0, \
  (p) == 4 ?(v) :0

void foo(int var1, int var2, int var3, int var4)
{
  printf("var1 = %d, var2 = %d, var3 = %d, var4 = %d\n", 
    var1, var2, var3, var4);
}

int main(void) 
{
  for (int i = 0; i < 5; ++i) 
  {
    printf("i = %d: ", i);
    foo(setACports(i, i));
  }
}

这输出:

i = 0: var1 = 0, var2 = 0, var3 = 0, var4 = 0
i = 1: var1 = 1, var2 = 0, var3 = 0, var4 = 0
i = 2: var1 = 0, var2 = 2, var3 = 0, var4 = 0
i = 3: var1 = 0, var2 = 0, var3 = 3, var4 = 0
i = 4: var1 = 0, var2 = 0, var3 = 0, var4 = 4

要在宏中检测 p<1 || p>4 的情况,您 可以 修改其中一个 ternary-operations 看起来像这样(在这种情况下是第一个):

  (p) == 1 \
    ?(v) \
    :((p) < 1 || (p) > 4 \
      ?fflush(stdout), fprintf(stderr, "Invalid: %d", v), exit(EXIT_FAILURE), -1 \
      :0), \

输出结果如下所示:

i = 0: Invalid: 0

请注意,宏不能跳过函数调用,只能调用函数或结束程序,如上例所示。

为了能够继续运行一个可以修改宏以实际执行函数调用:

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

#define setACports2(f, p, v) ( \
  ((p) < 1 || (p) > 4) \
    ? fflush(stdout), errno = ERANGE, perror(#f "()"), -1 \
    : ( \
      f( \
        (p) == 1 ?(v) :0, \
        (p) == 2 ?(v) :0, \
        (p) == 3 ?(v) :0, \
        (p) == 4 ?(v) :0 \
      ), 0 \
    ) \
  )

void foo(int var1, int var2, int var3, int var4)
{
  printf("var1 = %d, var2 = %d, var3 = %d, var4 = %d\n",
    var1, var2, var3, var4);
}

int main(void)
{
  for (int i = 0; i < 5; ++i)
  {
    int vi = i;
    printf("i = %d: ", i);
    if (-1 == setACports2(foo, i, vi))
    {
      fprintf(stderr, "setACports() failed\n");
    }
  }
}

这将输出:

i = 0: foo(): Numerical result out of range
setACports() failed
i = 1: var1 = 1, var2 = 0, var3 = 0, var4 = 0
i = 2: var1 = 0, var2 = 2, var3 = 0, var4 = 0
i = 3: var1 = 0, var2 = 0, var3 = 3, var4 = 0
i = 4: var1 = 0, var2 = 0, var3 = 0, var4 = 4

这一行

    if (-1 == setACports2(foo, i, vi))

将扩展为:

    if (-1 == ( ((i) < 1 || (i) > 4) ? fflush(stdout), errno = ERANGE, perror("foo" "()"), -1 : ( foo((i) == 1 ?(vi) :0, (i) == 2 ?(vi) :0, (i) == 3 ?(vi) :0, (i) == 4 ?(vi) :0), 0 ) ))

由于 setACports2 重复 setACports 可能 也像这样:

#define setACports2(f, p, v) ( \
  ((p) < 1 || (p) > 4) \
    ? fflush(stdout), errno = ERANGE, perror(#f "()"), -1 \
    : ( \
      f(setACports(p, v)), 0 \
    ) \
  )

与此答案相关的进一步阅读:

  • Seeing expanded C macros
  • What does the comma operator , do?
  • stderr and stdout - buffered vs. not buffered?
  • How to know what the 'errno' means?