1

我有一个看起来像这样的结构:

struct dgm_network_pkt {
    char    responder[INET_ADDRSTRLEN];
    int     num;
    char    **neighbors;
};

该字段num跟踪已分配和指向的字符数组的数量neighbors

现在我想构造一个包含标头和结构的数据包,并发送一个包含此数据包的 UDP 数据包。为了做到这一点,我需要做很多指针运算,以及对 sizeof() 的大量调用。例如,如果我的 header 是enum header hdr;,我的缓冲区是char *buf;并且我的 struct 的实例是struct mystruct stc;,我需要执行以下操作(片段):

buf = malloc(sizeof(stc.num * SIZEOF_EACH_ARRAY) + sizeof(hdr) + sizeof(stc.responder) + sizeof(int));

memcpy(buf, &hdr, sizeof(hdr)); /* Copy over header */
memcpy(buf + sizeof(hdr), &stc.responder, sizeof(stc.responder)); /* Copy 'responder' field */
memcpy(buf + dizeof(hdr) + sizeof(stc.responder), &stc.num, sizeof(int)); /* Copy num field */

然后一个循环复制指向的字符数组neighbors,再次sizeof()使用相同的参数多次调用。

如果您愿意看,这里是我用来完成所有这些的功能以供参考,但没有必要回答我的问题,并且可能会增加混乱(添加间接)。

int dismesh_compose_net_pkt(struct dgm_network_pkt *dismesh_sta, char **buf)
{
    int i;
    int pkt_size;
    enum dgm_header dgm_hdr;

    pkt_size = dismesh_sta->num * DISMESH_ETH_ADDR_STR + sizeof(dgm_hdr) 
        + sizeof(dismesh_sta->responder) + sizeof(int);

    dgm_hdr = NETWORK_STATUS_RESP;
    if ((*buf = malloc(pkt_size)) == NULL)
        return -1; 

    memcpy(*buf, &dgm_hdr, sizeof(dgm_hdr));
    memcpy(*buf + sizeof(dgm_hdr), &dismesh_sta->responder, sizeof(dismesh_sta->responder));
    memcpy(*buf + sizeof(dgm_hdr) + sizeof(dismesh_sta->responder), &dismesh_sta->num, sizeof(int));

    /* Copy contents of neighbors to buffer */
    for (i = 0; i < dismesh_sta->num; i++) {
        memcpy(*buf + sizeof(dgm_hdr) + sizeof(dismesh_sta->responder) + sizeof(int) + i * DISMESH_ETH_ADDR_STR,
                *(dismesh_sta->neighbors + i), DISMESH_ETH_ADDR_STR);
        DGM_LOG("Packed up neighbor %d\n", i); 
    }   

    return pkt_size;
}

这里是:

我注意到我sizeof()一遍又一遍地使用相同的参数调用很多:将结构的内容复制到缓冲区,每个元素的大小等等。有没有更好的方法来做到这一点?我在想我可以在我的头文件中包含一些#defines,比如说,我可以在其中执行#define OFFSET_RESPONDER sizeof(hdr), #define OFFSET_NUM OFFSET_RESPONDER + sizeof(mystruct.responder), and#define SIZE_HEADER sizeof(dgm_header)等等。如果保持原样,我会注意到显着的性能损失吗?编译器(在我的情况下是 GCC)是否对此进行了优化?你认为#defines 会降低可读性吗?清理此代码的最佳方法是什么?

4

5 回答 5

2

sizeof()不是函数,它在编译阶段进行评估。因此,改变 a 的许多sizeof(something)出现#define CONSTANT不应该改变任何性能,它只会改变编译时间,但我认为它可以忽略不计。

唯一重要的方面是代码的可读性。两者都适合我,你决定。

于 2013-06-28T19:44:30.060 回答
2

首先,sizeof是运算符,而不是函数,因此编译器会将其转换为单个数字。

二、看offsetof宏观;我认为它会完全满足您的需求。

于 2013-06-28T19:46:17.643 回答
1

您的编译器肯定会对此进行优化。我不会通过在各处散布非语义魔法令牌来牺牲代码可读性。

您可以检查编译器输出来验证这一点,但到处都是常量。

于 2013-06-28T19:32:41.853 回答
1

sizeof是一个内置的前缀运算符。它在编译时进行评估,除非它的参数是 C99 风格的可变长度数组。在后一种情况下,它是在运行时评估的。

值得注意的是,sizeof只有类型才需要在参数周围加上括号。iesizeof(dismesh_sta->responder)可以替换为sizeof dismesh_sta->responder,这样可以节省输入一个字符。

于 2013-06-28T19:53:38.787 回答
1

在运行时评估的唯一情况sizeof是应用于可变长度数组 (VLA)。在所有其他情况下,它被替换为编译时常量。即没有sizeof多次评估相同的开销离子。它在代码中看起来不太漂亮,可能会产生一些维护开销,但不会影响性能。

将这些sizeof评估隐藏在宏后面不会真正改变任何性能,因为宏只是文本替换。这意味着实际代码在编译器看来将完全相同。然而,对宏的深思熟虑的使用实际上可能会提高重复代码的可读性。

于 2013-06-28T19:48:35.177 回答