Chinaunix首页 | 论坛 | 博客
  • 博客访问: 463413
  • 博文数量: 137
  • 博客积分: 3874
  • 博客等级: 中校
  • 技术积分: 1475
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-05 10:50
文章分类

全部博文(137)

文章存档

2011年(37)

2010年(100)

分类: LINUX

2010-09-06 16:43:29

  • 问题内容:结构体最后定义一个char p[0];这样的成员有何意义?多谢!
  • 原讨论链接:
  • 所属论坛:     审核组:
  • 提问者:     解决者:
  • 感谢:
  • 关键字:
  • 答案:

    struct ast_exten { 
    char *exten; /* Extension name */ 
    int matchcid; /* Match caller id ? */ 
    char *cidmatch; /* Caller id to match for this extension */ 
    int priority; /* Priority */ 
    char *label; /* Label */ 
    struct ast_context *parent; /* The context this extension belongs to  */ 
    char *app;  /* Application to execute */ 
    void *data; /* Data to use (arguments) */ 
    void (*datad)(void *); /* Data destructor */ 
    struct ast_exten *peer; /* Next higher priority with our extension */ 
    const char *registrar; /* Registrar */ 
    struct ast_exten *next; /* Extension with a greater ID */ 
    char stuff[0]; 
    }; 

    最近看asterisk的源码,发现很多的结构体最后都定义了一个元素个数为0个的数组,不知道有何意义,望各位大侠指点,非常感谢!! 

    又如: 
    struct ast_include { 
    char *name;
    char *rname; /* Context to include */ 
    const char *registrar; /* Registrar */ 
    int hastime; /* If time construct exists */ 
    struct ast_timing timing;               /* time construct */ 
    struct ast_include *next; /* Link them together */ 
    char stuff[0]; 
    }; 

    struct ast_ignorepat { 
    const char *registrar; 
    struct ast_ignorepat *next; 
    char pattern[0]; 
    }; 

    来自asterisk的源码中的Pbx.c 文件 
    --------------------------------------------------------------- 

    这是个广泛使用的常见技巧,常用来构成缓冲区。比起指针,用空数组有这样的优势: 
    1.不需要初始化,数组名直接就是所在的偏移 
    2.不占任何空间,指针需要占用int长度空间,空数组不占任何空间。 

    “这个数组不占用任何内存”,意味着这样的结构节省空间;“该数组的内存地址就和他后面的元素的地址相同”,意味着无需初始化,数组名就是后面元素的地址,直接就能当做指针使用。 

    这样的写法最适合制作动态buffer。因为可以这样分配空间: 
    malloc(sizeof(struct XXX)+ buff_len); 
    看出来好处没有?直接就把buffer的结构体和缓冲区一块分配了。用起来也非常方便,因为现在kongsuzu其实变成了buff_len长度的数组了。 
    这样的好处是: 
    一次分配解决问题,省了不少麻烦。大家知道为了防止内存泄漏,如果是分两次分配(结构体和缓冲区),那么要是第二次malloc失败了,必须回滚释放第一个分配的结构体。这样带来了编码麻烦。其次,分配了第二个缓冲区以后,如果结构里面用的是指针,还要为这个指针赋值。同样,在free这个buffer的时候,用指针也要两次free。如果用空数组,所有问题一次解决。 
    其次,大家知道小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了,在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题。 

    如此看来,用空数组既简化编码,又解决了小内存碎片问题提高了性能,何乐不为?应该广泛采用。 

    如果你做过操作系统的开发或者嵌入式开发,这种技巧应该是见得滥了呵呵。 
    --------------------------------------------------------------- 

    这个就是newbiestar() 所说的extension flexible array member,是C99允许的。标准原文如下(第117页): 

    As a special case, the last element of a structure with more than one named member may 
    have an incomplete array type; this is called a flexible array member. With two 
    exceptions, the flexible array member is ignored. First, the size of the structure shall be 
    equal to the offset of the last element of an otherwise identical structure that replaces the 
    flexible array member with an array of unspecified length.106) Second, when a . (or ->) 
    operator has a left operand that is (a pointer to) a structure with a flexible array member 
    and the right operand names that member, it behaves as if that member were replaced 
    with the longest array (with the same element type) that would not make the structure 
    larger than the object being accessed; the offset of the array shall remain that of the 
    flexible array member, even if this would differ from that of the replacement array. If this 
    array would have no elements, it behaves as if it had one element but the behavior is 
    undefined if any attempt is made to access that element or to generate a pointer one past 
    it. 


    --------------------------------------------------------------- 

    这个东西,我在busybox的源码中也见过, 
    其实就是便于扩展,至于你说的那很小很小概率的情况, 
    如果你另外成员都有define的话,就不要这么用好了啊 

    关于到了c++中, 
    由于内存布局的不可预料性,这样的结构就不要用拉 
    因为c++的内存布局不是说你写在最后边,分配的地址就在 
    最后边拉 
    这个问题inside里边曾有提及 
    --------------------------------------------------------------- 
    --------------------------------------------------------------- 

    关于这个问题,从楼主的代码来看,存在几个需要弄清楚的地方。第一,char p[0]是否合法;其次,如果非法,按照标准,合法的代码是怎样的? 

    先解释第一点,在ISO/IEC 9899-1999里面,这么写铁定是非法的,这个仅仅是GNU C的扩展,gcc可以允许这一语法现象的存在。考虑以下代码: 
    #include  

    int main(int argc, char* argv[]) 

            char ia[0]; 
            printf("%d\n", sizeof(ia)); 
            return 0; 

    这个在gcc里面编译,即使你使用了-Wall参数,gcc仍然会让这段代码通过……如果需要强制编译器按照ISO C标准进行编译,你需要给出-pedantic(或者-pedantic_error)参数,这样,编译器会报告:ISO C forbids zero-size array `ia' 
    这个仅仅是在C99没有出台的情况下,gcc为了使用类似于C99 

阅读(999) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~