在C中调用宏,结果如何?
我继承了一些C代码,对宏有点生疏。我们使用创建数据包。我有这样做的代码:在C中调用宏,结果如何?,c,macros,C,Macros,我继承了一些C代码,对宏有点生疏。我们使用创建数据包。我有这样做的代码: ip_pack_hdr( /* hdr = */ &(pkt->ip), /* tos = */ 0, // Fixed /* len = */ ICMP4_ECHO_PKT_LEN_NO_ETH + data_len, // Fixed /* id = */ 0, // Dynamic (self)
ip_pack_hdr(
/* hdr = */ &(pkt->ip),
/* tos = */ 0, // Fixed
/* len = */ ICMP4_ECHO_PKT_LEN_NO_ETH + data_len, // Fixed
/* id = */ 0, // Dynamic (self)
/* off = */ IP_DF, // Fixed
/* ttl = */ 0, // Dynamic (caller)
/* p = */ IP_PROTO_ICMP, // Fixed
/* src = */ src.addr_ip, // Fixed
/* dst = */ dst.addr_ip // Fixed
);
libdnet中ip_pack_hdr的定义是
#define ip_pack_hdr(hdr, tos, len, id, off, ttl, p, src, dst) do { \
struct ip_hdr *ip_pack_p = (struct ip_hdr *)(hdr); \
ip_pack_p->ip_v = 4; ip_pack_p->ip_hl = 5; \
ip_pack_p->ip_tos = tos; ip_pack_p->ip_len = htons(len); \
ip_pack_p->ip_id = htons(id); ip_pack_p->ip_off = htons(off); \
ip_pack_p->ip_ttl = ttl; ip_pack_p->ip_p = p; \
ip_pack_p->ip_src = src; ip_pack_p->ip_dst = dst; \
} while (0)
我试图理解调用宏时到底发生了什么。我理解为什么会有do-while(0)循环,但我不理解的是,这个宏是否会就地修改我的数据?它应该像函数一样工作,但ip包的最终值存储在哪里?在编译之前,代码会被替换。这就好像你直接在使用宏的地方写代码一样。宏与函数不同,从这个意义上讲,您不能“调用”宏
do{}while(0)
只是一种简单的封装代码块的方法,请注意,它永远不会循环,只执行一次。它还创建一个作用域,并允许一个
放在宏之后,因此它看起来像函数调用,但实际上不是
此外,代码在一行中展开,这使得调试非常困难。您可以通过使用适当的标志调用编译器来查看预处理的结果,检查生成的文件或代码,这样您会更好地理解它。编译前代码会被替换。这就好像你直接在使用宏的地方写代码一样。宏与函数不同,从这个意义上讲,您不能“调用”宏
do{}while(0)
只是一种简单的封装代码块的方法,请注意,它永远不会循环,只执行一次。它还创建一个作用域,并允许一个
放在宏之后,因此它看起来像函数调用,但实际上不是
此外,代码在一行中展开,这使得调试非常困难。通过使用适当的标志调用编译器,您可以看到预处理的结果,检查生成的文件或代码,您将更好地理解它。没有“调用”宏的事情,因为宏在编译时展开,而调用(如果有的话)发生在运行时。预处理器是C编译器的第一个状态,它扩展宏以供C编译器的翻译阶段使用
当prprocessor展开宏时,它会变成:
struct ip_hdr *ip_pack_p = (struct ip_hdr *)(&(pkt->ip));
ip_pack_p->ip_v = 4;
ip_pack_p->ip_hl = 5;
ip_pack_p->ip_tos = 0;
ip_pack_p->ip_len = htons(ICMP4_ECHO_PKT_LEN_NO_ETH + data_len);
ip_pack_p->ip_id = htons(0);
ip_pack_p->ip_off = htons(IP_DF);
ip_pack_p->ip_ttl = 0;
ip_pack_p->ip_p = IP_PROTO_ICMP;
ip_pack_p->ip_src = src.addr_ip;
ip_pack_p->ip_dst = dst.addr_ip;
整个代码块被包装在do
/中,而(0)
()。您提供给ip\u pack\u hdr
的宏参数会被逐字复制到相应宏参数所指示的位置。没有“调用”宏这样的事情,因为宏在编译时展开,而调用(如果有)发生在运行时。预处理器是C编译器的第一个状态,它扩展宏以供C编译器的翻译阶段使用
当prprocessor展开宏时,它会变成:
struct ip_hdr *ip_pack_p = (struct ip_hdr *)(&(pkt->ip));
ip_pack_p->ip_v = 4;
ip_pack_p->ip_hl = 5;
ip_pack_p->ip_tos = 0;
ip_pack_p->ip_len = htons(ICMP4_ECHO_PKT_LEN_NO_ETH + data_len);
ip_pack_p->ip_id = htons(0);
ip_pack_p->ip_off = htons(IP_DF);
ip_pack_p->ip_ttl = 0;
ip_pack_p->ip_p = IP_PROTO_ICMP;
ip_pack_p->ip_src = src.addr_ip;
ip_pack_p->ip_dst = dst.addr_ip;
整个代码块被包装在do
/中,而(0)
()。您提供给ip_pack_hdr
的宏参数将被逐字复制到相应宏参数指示的位置
在C中调用宏,结果如何
宏是文本替换。结果取决于它是如何形成的
注意:宏文本替换发生在注释变为空白之后
考虑intputc(intc,文件*stream)代码>。实现可以使putc()
成为真正的函数,也可以作为宏实现。在后一种情况下,由于宏是按这种方式设计的,因此结果为int
考虑以下几点。宏SEMI
的作用不大,因为它不尝试模拟函数,也不形成可返回的结果
#define SEMI(a) ;
int main() {
SEMI(nothing)
}
OP的宏ip\u pack\u hdr()
ip_pack_hdr(
/* hdr = */ &(pkt->ip),
/* tos = */ 0, // Fixed
/* len = */ ICMP4_ECHO_PKT_LEN_NO_ETH + data_len, // Fixed ...
....
变成一条长线
do { struct ip_hdr *ip_pack_p = (struct ip_hdr *)( &(pkt->ip)); ip_pack_p->ip_v = 4; ip_pack_p->ip_hl = 5; ip_pack_p->ip_tos = 0; ip_pack_p->ip_len = htons( ICMP4_ECHO_PKT_LEN_NO_ETH + data_len); ...
在C中调用宏,结果如何
宏是文本替换。结果取决于它是如何形成的
注意:宏文本替换发生在注释变为空白之后
考虑intputc(intc,文件*stream)代码>。实现可以使putc()
成为真正的函数,也可以作为宏实现。在后一种情况下,由于宏是按这种方式设计的,因此结果为int
考虑以下几点。宏SEMI
的作用不大,因为它不尝试模拟函数,也不形成可返回的结果
#define SEMI(a) ;
int main() {
SEMI(nothing)
}
OP的宏ip\u pack\u hdr()
ip_pack_hdr(
/* hdr = */ &(pkt->ip),
/* tos = */ 0, // Fixed
/* len = */ ICMP4_ECHO_PKT_LEN_NO_ETH + data_len, // Fixed ...
....
变成一条长线
do { struct ip_hdr *ip_pack_p = (struct ip_hdr *)( &(pkt->ip)); ip_pack_p->ip_v = 4; ip_pack_p->ip_hl = 5; ip_pack_p->ip_tos = 0; ip_pack_p->ip_len = htons( ICMP4_ECHO_PKT_LEN_NO_ETH + data_len); ...
C中的“宏”是一个简单的字符串替换(包括参数替换),由C预处理器(在Linux上,即cpp foo.C
)在编译完成之前完成。只需在源代码上运行C预处理器,即可查看宏是如何展开的。它并不完全像一个函数。如上所述,宏没有被“调用”。@EugeneSh.:宏什么时候被“调用过”?该宏正在招惹麻烦,而强制转换已经被调用了。不要太喜欢宏@Olaf“天是蓝的,它不是红的”,并不意味着它永远是红的。C中的“宏”是一个简单的字符串替换(包括参数替换),由C预处理器(在Linux上,即cpp foo.C
)在编译完成之前进行。只需在源代码上运行C预处理器,即可查看宏是如何展开的。它并不完全像一个函数。如上所述,宏没有被“调用”。@EugeneSh.:宏什么时候被“调用过”?该宏正在招惹麻烦,而强制转换已经被调用了。不要太喜欢宏@Olaf“如果天空是蓝色的,它就不是红色的”,这并不意味着它永远是红色的。非常感谢,这确实帮助我理解这一点。宏扩展是否包括/*hdr=*/
?也许不是。@chux这是一个很好的问题-我几乎可以肯定预处理器会删除所有注释,包括宏扩展中的注释。我必须试着看看它是否发生了。嗯,我认为C会删除注释并用WhitePac替换它们