赋值宏编写
Assignment macro writing
我正在尝试为 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);
我之前一直收到错误的意外表达式;
感谢您的快速回复,
看起来我更倾向于函数调用而不是宏,因为加班可能会很麻烦。
与使用函数调用而不是宏相比,是否有任何性能影响?
宏的情况很糟糕。你可以试试
#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
-s 和 if (dst == src) return;
没用,您可以删除它们。
#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)
I am trying to write a macro for the following repeated code inside the for loop.
请不要。它只有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;
}
宏
#define COPY(x,y,z) \
a->x = x;\
...
对于 a->x = 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)
.
内的习惯
这个定义:
#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都被替换了,所以首先更改为唯一标识符。其次,不要在定义中对 copy-to 元素进行编码。在您的情况下,这是一个,将其传递给宏:
#define COPY( dest, x_copy, y_copy, z_copy ) \
dest->x = x_copy; \
dest->y = y_copy; \
dest->z = z_copy;
您也落入了 if 后跟一个多语句宏的陷阱,它显然不会按照您的预期执行,因为您没有用花括号将多行宏括起来!在 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);
}
我正在尝试为 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);
我之前一直收到错误的意外表达式;
感谢您的快速回复, 看起来我更倾向于函数调用而不是宏,因为加班可能会很麻烦。 与使用函数调用而不是宏相比,是否有任何性能影响?
宏的情况很糟糕。你可以试试
#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
-s 和 if (dst == src) return;
没用,您可以删除它们。
#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)
I am trying to write a macro for the following repeated code inside the for loop.
请不要。它只有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;
}
宏
#define COPY(x,y,z) \
a->x = x;\
...
对于 a->x = 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)
.
这个定义:
#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都被替换了,所以首先更改为唯一标识符。其次,不要在定义中对 copy-to 元素进行编码。在您的情况下,这是一个,将其传递给宏:
#define COPY( dest, x_copy, y_copy, z_copy ) \
dest->x = x_copy; \
dest->y = y_copy; \
dest->z = z_copy;
您也落入了 if 后跟一个多语句宏的陷阱,它显然不会按照您的预期执行,因为您没有用花括号将多行宏括起来!在 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);
}