我继承了一些C代码,我在宏上有点生疏。我们使用libdnet来创建数据包。我有代码执行此操作:
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)
我试图了解调用宏时到底发生了什么。我从this SO question了解为什么有一个do-while(0)循环,但我不明白的是这个宏是否修改了我的数据?它应该像一个函数,但ip_pack_p的最终值存储在哪里?
答案 0 :(得分:6)
没有“调用”宏这样的东西,因为宏在编译时被扩展,而调用(如果有的话)在运行时发生。预处理器,C编译器的第一个状态,扩展您的宏,供C编译器的翻译阶段使用。
当prprocessor扩展你的宏时,它变为:
curl -XPUT -H "Content-Type: application/json" \
-d '[{"lang": "ENGLISH","fields": [{ "name": "id", "value": 1 }]}]' \
http://localhost:9090/services/rest/index/my_index/document?login=lorem&key=08762e43getye0042f875e86eaiu687f
整个代码块都包含在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
(why?)中。您提供给while(0)
的宏参数将逐字复制到相应宏参数指示的位置。
答案 1 :(得分:1)
代码在编译之前被替换。因此,就像您直接在使用宏的地方编写代码一样。宏不是一个功能,从这个意义上说,你可以" 调用"一个宏。
do { } while (0)
只是一种简单的方法来封闭代码块,请注意,这将永远不会循环,它只执行一次。它还创建了一个范围,并允许在宏之后放置;
,因此看起来像一个函数调用,但它不是。
此外,代码扩展为一行,这使得调试非常困难。您可以通过使用适当的标志调用编译器来查看预处理的结果,检查生成的文件或代码,您将更好地理解它。
答案 2 :(得分:1)
在C中调用宏,结果是什么?
宏是文本替换。结果取决于它是如何形成的。
注意:在将注释更改为空格后,会发生宏文本替换。
考虑int putc(int c, FILE *stream);
。实现可以使putc()
成为真正的函数或实现为宏。在后一种情况下,int
中的结果因为宏是这样设计的。
请考虑以下事项。宏SEMI
没有做太多,因为它没有尝试模拟函数并且不会形成可返回的结果
#define SEMI(a) ;
int main() {
SEMI(nothing)
}
OP的宏ip_pack_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); ...