[转]数组大小为0的应用

发布时间:2011-7-6 11:04
分类名称:C++


在linuxforum上看见有人讨论数组大小为0的理解,觉得不错,特摘录下来,以备参考:
Q: 数组大小为0应该怎么理解?
比如:
struct page *page[0];
unsigned long private[0] ____cacheline_aligned;

A: 一个很好的例子就是
struct unix_address
{
atomic_t refcnt;
int len;
unsigned hash;
struct sockaddr_un name[0];
};

#define UNIX_PATH_MAX 108

struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};

其中name实际上指向unix_address结构之后的空间。
好处就是sockaddr_un是变长的,为了不浪费空间,就这样定义。到实际分配unix_address结构的时候按实际的地址大小一并分配空间,那样就可以通过unix_address->name来访问实际的地址。

这样做的具体的优点:
struct unix_address
{
atomic_t refcnt;
int len;
unsigned hash;
void *name;
};

1。name占用空间(4字节)
2。分配空间的时候可以一起分配,但是需要把p->name设置为=p++,访问name的值时需要指针中
转一下


struct unix_address
{
atomic_t refcnt;
int len;
unsigned hash;
struct sockaddr_un name[0];
};
没有上面两个缺点
1。它不占用结构的空间
2。如果访问某个p->name,却可以访问紧接p的内存空间
利用上面两个特性,就可以根据实际的unix域地址大小来一起分配空间,通过p->name访问地址


-------------------------------------------------------------------
| |实际地址|
-------------------------------------------------------------------
^ ^
| |
p name

它可以用来定义一个变长的结构体,比如你可以动态分配这个结构体,并把分配的长度等于sizeof(struct) + len,这样len这么长的内存就可以直接用最后的那个没有实际空间的指针来引用了。

 

下面是自己写的例子:=======================================================

#include <iostream>
using namespace std;

#define UNIX_PATH_MAX 108

struct sockaddr_un {
    int sun_family;
    char sun_path[UNIX_PATH_MAX];
};

struct unix_address
{
    int refcnt;
    int len;
    unsigned hash;
    struct sockaddr_un name[0];
};

struct unix_address2
{
    int refcnt;
    int len;
    unsigned hash;
    struct sockaddr_un *name;
};

struct unix_address3
{
    int refcnt;
    int len;
    unsigned hash;
    void *name;
};

int main(int argc, char* argv[])
{
    cout << sizeof(unix_address) << endl;
    cout << sizeof(unix_address2) << endl;
    cout << sizeof(unix_address3) << endl;

    unix_address *p = (unix_address *)malloc(sizeof(unix_address) + sizeof(sockaddr_un));
    p->name->sun_family = 1;
    memset(p->name->sun_path, 0, UNIX_PATH_MAX);

    unix_address2 *p2 = (unix_address2 *)malloc(sizeof(unix_address2) + sizeof(sockaddr_un));
    p2->name = (sockaddr_un *)(void *)(p2+1);
    p2->name->sun_family = 1;
    memset(p2->name->sun_path, 0, UNIX_PATH_MAX);


    unix_address3 *p3 = (unix_address3 *)malloc(sizeof(unix_address3) + sizeof(sockaddr_un));
    p3->name = p3+1;
    ((sockaddr_un *)(p3->name))->sun_family = 1;
    memset(((sockaddr_un *)(p3->name))->sun_path, 0, UNIX_PATH_MAX);

    free(p);
    free(p2);
    free(p3);
    return 0;
}