我正在尝试为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);
我之前一直收到错误的意外表达;
感谢您的快速回复, 看起来我更倾向于函数调用而不是宏,因为它可能会加速繁琐。 是否有使用函数调用而不是宏的性能影响?
答案 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;
或者,假设您确定a
和b
没有别名(不是相同的地址)且不重叠,您可以
memcpy(a, b, sizeof(struct my_st));
如果结构包含的字段数超过x
,y
,z
,但您只想复制它们,请制作一个合适的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);
}