作业宏写作

时间:2015-03-13 10:04:06

标签: c c-preprocessor

我正在尝试为for循环中的以下重复代码编写一个宏。

for(i=0; i<n; i++) {
 a->x = b->x;
 a->y = b->y;
 a->z = b->z;
}
for(j=0;j<n;j++){
 a->x = c->x;
 a->y = c->y;
 a->z = c->z;
}

---------
with macro
#define COPY(x,y,z) \
a->x = x;\
a->y = y;\
a->z = z;\

for(i=0;i<n;i++)
 COPY(b->x,b->y,b->z);
for(i=0;i<n;i++)
 COPY(c->x,c->y,c->z);

我之前一直收到错误的意外表达;


感谢您的快速回复, 看起来我更倾向于函数调用而不是宏,因为它可能会加速繁琐。 是否有使用函数调用而不是宏的性能影响?

5 个答案:

答案 0 :(得分:7)

  

我正在尝试为for循环中的以下重复代码编写一个宏。

请不要。它只有3行。您所要做的就是用晦涩难懂的家庭酿造语言语法来破坏您的代码。你已经设法写了一个致命的错误:不使用{}作为宏。在大多数情况下,类似函数的宏是非常糟糕的做法。

首先,是否有理由不能写*a = *b;

如果有这样的理由,那么请考虑做这样的事情:

typedef struct // given this struct
{
  int x;
  int y;
  int z;
} xyz_t;

void xyz_copy (xyz_t* dest, const xyz_t* source)
{
  dest->x = source->x;
  dest->y = source->y;
  dest->z = source->z;
}

答案 1 :(得分:3)

宏是一个不好的情况。你可以试试

#define COPYxyz(Dst,Src) do {   \
    (Dst)->x = (Src)->x;        \
    (Dst)->y = (Src)->y;        \
    (Dst)->z = (Src)->z;        \
   } while(0)

(请注意do{ ... }while(0)在宏中是一个非常古老的useful trick

然后是代码COPYxyz(a,b)(但是COPYxyz(p++,--q)COPYxyz(++p,p)是一场灾难,这就是编写这样一个宏的原因很糟糕的原因)

但是,如果你有

  struct my_st  {int x, int y, int z};
  struct my_st *a = something();
  struct my_st *b = otherthing();

您只需编写结构分配代码:

     *a = *b;

或者,假设您确定ab没有别名(不是相同的地址)且不重叠,您可以

     memcpy(a, b, sizeof(struct my_st));

如果结构包含的字段数超过xyz,但您只想复制它们,请制作一个合适的inline function

static inline void copy_xyz(struct my_st*dst, const struct my_st*src) {
   assert (src != NULL);
   assert (dst != NULL);
   if (dst == src) return;
   dst->x = src->x;
   dst->y = src->y;
   dst->z = src->z;
   /// remaining fields are not copied!
}

然后,您将无忧无虑地编码copy_xyz(p++,p),它应该与COPYxyz宏一样高效。如果您确定它们没用,可以删除assert - 和if (dst == src) return;

答案 2 :(得分:0)

#define COPY(x,y,z) \
a->x = x;\
a->y = y;\
a->z = z;
当你通过

COPY(b->x,b->y,b->z);

然后你有

a->b->x = b->x;
a->b->y = b->y;
a->c->y = c->y;;

这不是你需要的。 所以你需要用

替换它
#define COPY(p,q,r) do{\
a->x = p;\
a->y = q;\
a->z = r;\
}while(0)

答案 3 :(得分:0)

#define COPY(x,y,z) \
a->x = x;\
...
对于x中的两次出现,

都将替换a->x = x;,例如 COPY(b->x, ...)给出a->b->x = b->x,因此请使用其他名称作为宏参数。


请注意

for(i=0;i<n;i++)
 COPY(b->x,b->y,b->z);

将扩展为

for(i=0; i<n; i++)
  a->x = b->x;
a->y = b->y;
a->z = b->z;

这不是你想要的。永远将宏体置于do { ... } while (0)

答案 4 :(得分:0)

这个定义:

#define COPY(x,y,z) \
a->x = x;\
a->y = y;\
a->z = z;\

使用for循环

for(i=0;i<n;i++)
    COPY(b->x,b->y,b->z);
for(i=0;i<n;i++)
    COPY(c->x,c->y,c->z);

这导致了这个快速测试:

#include <stdio.h>

#define COPY(x,y,z) \
    a->x = x;\
    a->y = y;\
    a->z = z;\

int main( int argc, char* argv[] )
{
    for(i=0;i<n;i++)
        COPY(b->x,b->y,b->z);

    for(i=0;i<n;i++)
        COPY(c->x,c->y,c->z);
}

仅预处理:gcc -E main.c > main.i

给出

int main( int argc, char* argv[] )
{
    int i;

    for(i=0;i<n;i++)
        a->b->x = b->x; a->b->y = b->y; a->b->z = b->z;;

    for(i=0;i<n;i++)
        a->c->x = c->x; a->c->y = c->y; a->c->z = c->z;;
}

有很多错误!

您有两个位置a->x = x中的宏替换,因为两个x都被替换,因此首先更改为唯一标识符。其次,不要在define中编码copy-to元素。在你的情况下,这是一个,将这个东西传递给宏:

#define COPY( dest, x_copy, y_copy, z_copy ) \
    dest->x = x_copy; \
    dest->y = y_copy; \
    dest->z = z_copy;

你也陷入了陷阱,如果后面跟着一个多语句宏,这显然不会按你的意图执行,因为你没有用花括号包围多行宏!在do{ } while(0)中包含多个行宏以便按照您的预期使用它们的常见做法是:

#define COPY( dest, x_copy, y_copy, z_copy ) \
    do { \
    dest->x = x_copy; \
    dest->y = y_copy; \
    dest->z = z_copy; \
    } while(0)

现在,将您的新宏替换为我们希望能够正常工作的输出:

#include <stdio.h>

#define COPY( dest, x_copy, y_copy, z_copy ) \
    do { \
    dest->x = x_copy; \
    dest->y = y_copy; \
    dest->z = z_copy; \
    } while(0)

int main( int argc, char* argv[] )
{
    int i;

    for(i=0;i<n;i++)
        COPY(a, b->x,b->y,b->z);

    for(i=0;i<n;i++)
        COPY(a, c->x,c->y,c->z);
}

同样,gcc -E main.c > main.i会导致从宏扩展正确的代码:

int main( int argc, char* argv[] )
{
    int i;

    for(i=0;i<n;i++)
        do { a->x = b->x; a->y = b->y; a->z = b->z; } while(0);

    for(i=0;i<n;i++)
        do { a->x = c->x; a->y = c->y; a->z = c->z; } while(0);
}