admin管理员组

文章数量:1638924

最近看别人的代码,发现中间有这样的使用:

tmp->FileName[i];

其中tmp是一个指针,指针类型是FILE_NOTIFY_INFORMATION *的。而FILE_NOTIFY_INFORMATION 的定义是这样的:

typedef struct _FILE_NOTIFY_INFORMATION {
    DWORD NextEntryOffset;
    DWORD Action;
    DWORD FileNameLength;
    WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;

可以看到,FileName是一个固定大小字符数组,他的大小是1,开头的tmp->FileName[i];中的i是大于1的,为什么使用起来不会崩溃呢?

原来这和tmp的定义方式有关。

  char notify[1024];
  FILE_NOTIFY_INFORMATION *tmp=(FILE_NOTIFY_INFORMATION *)notify;

然后对tmp进行填充,如果填充后的长度大于了FILE_NOTIFY_INFORMATION的长度,那么就是说FileName的实际可引用的范围就变大了。为什么呢?

因为tmp不是一个FILE_NOTIFY_INFORMATION 结构,而是指针的方式,它是将一段已经分配好的内存强制转换成FILE_NOTIFY_INFORMATION *格式的,由于最后一个成员的定义是字符数组,而字符数组的规矩是遇到零字符结束,所以只要FileName[0]和后面紧跟的字符不是非零字符,他的引用就不会结束,直到遇到零字符。

但是这也不是没有限制的,FileName的引用大小不可以超过1024 - 3 * dword的大小,否则就会越界了。


  经1楼老兄的指点,在下也知道了这种用法的正式名称——柔性数组,下面是介绍这种用法的比较常见的文章,拿来享用一下吧。


C99 柔性数组结构成员

 

  • 结构体变长的妙用——0个元素的数组 

    有时我们需要产生一个结构体,实现了一种可变长度的结构。如何来实现呢? 
    看这个结构体的定义: 
    typedef struct st_type 

      int nCnt; 
      int item[0]; 
    }type_a; 
    (有些编译器会报错无法编译可以改成:) 
    typedef struct st_type 

      int nCnt; 
      int item[]; 
    }type_a; 
    这样我们就可以定义一个可变长的结构,用sizeof(type_a)得到的只有4,就是sizeof(nCnt)=sizeof(int)那 个0个元素的数组没有占用空间,而后我们可以进行变长操作了。 
    C语言版: 
    type_a *p = (type_a*)malloc(sizeof(type_a) + 100*sizeof(int)); 
    C++语言版: 
    type_a *p = (type_a*)new char[sizeof(type_a) + 100*sizeof(int)]; 
    这样我们就产生了一个长为100的type_a类型的东西用p->item[n]就能简单地访问可变长元素,原理十分简单 ,分配了比sizeof(type_a)多的内存后int item[];就有了其意义了,它指向的是int nCnt;后面的内容,是没 有内存需要的,而在分配时多分配的内存就可以由其来操控,是个十分好用的技巧。 
    而释放同样简单: 
    C语言版: 
    free(p); 
    C++ 语言版: 
    delete []p; 
    其实这个叫灵活数组成员(fleible array member)C89不支持这种东西,C99把它作为一种特例加入了标准。但 是,C99所支持的是incomplete type,而不是zero array,形同int item[0];这种形式是非法的,C99支持的 形式是形同int item[];只不过有些编译器把int item[0];作为非标准扩展来支持,而且在C99发布之前已经有 了这种非标准扩展了,C99发布之后,有些编译器把两者合而为一。

本文标签: 柔性数组使用说明FILENOTIFYINFORMATION