我正在为一个类项目编程一个简单的包嗅探器。有一段时间,我遇到了一个问题,一个包的源和目的地似乎是相同的。例如,以太网帧的源和目的地将始终是相同的MAC地址。我定制了ether_ntoa(char *),因为Windows不像Linux那样有ethernet.h。代码段如下:

char *ether_ntoa(u_char etheraddr[ETHER_ADDR_LEN])
{
    int i, j;
    char eout[32];

    for(i = 0, j = 0; i < 5; i++)
    {
        eout[j++] = etheraddr[i] >> 4;
        eout[j++] = etheraddr[i] & 0xF;
        eout[j++] = ':';
    }
    eout[j++] = etheraddr[i] >> 4;
    eout[j++] = etheraddr[i] & 0xF;
    eout[j++] = '\0';
    for(i = 0; i < 17; i++)
    {
        if(eout[i] < 10)
            eout[i] += 0x30;
        else if(eout[i] < 16)
            eout[i] += 0x57;
    }
    return(eout);
}

我通过使用malloc()让编译器分配内存来解决这个问题(即,我使用char eout[32]而不是char * eout; eout = (char *) malloc (32);)。但是,我认为编译器在编译时为一个char数组指定不同的内存位置。这不正确吗?

最佳答案

正如其他人指出的,您不能返回指向具有自动存储持续时间的对象的指针——当eout超出范围时,它不再存在。GCC实际上警告您:

ether_ntoa.c: In function ‘ether_ntoa’:
ether_ntoa.c:26: warning: function returns address of local variable

实现所需结果的通常方法是让调用者负责分配目的地。例如:
int ether_ntoa(unsigned char etheraddr[ETHER_ADDR_LEN], char *dest, size_t len)
{
    return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
        (unsigned)etheraddr[0],
        (unsigned)etheraddr[1],
        (unsigned)etheraddr[2],
        (unsigned)etheraddr[3],
        (unsigned)etheraddr[4],
        (unsigned)etheraddr[5]);
}

(还要注意,您的手工编码转换例程可以替换为一个简单的snprintf()调用)。你可以这样称呼它:
char eout[32];
ether_ntoa(etheraddr, eout, sizeof eout);
/* Converted address is now in eout */

Linux上的ether_ntoa()函数使用不同的方法-它将函数中的缓冲区声明为static。如果您这样做了,那么您的eout将在程序的生命周期内有效,因此您可以返回指向它的指针。缺点是只有一个eout-每次调用ether_ntoa,它将覆盖前一个。

10-06 04:24