您的位置:首页 > 其它

零长数组剖析

2016-05-05 21:36 323 查看
想必在阅读内核代码中,大家经常会遇到零长数组,该语法归GUN C特有,标准C和C++都不具备该性能。出于好奇,所以通过编写代码来分析零长数组使用方法,同时用来研究零长数组的特点。

zero_array.c为研究零长数组代码,log.txt为程序运行后输出信息。为了供大家参考及体现真实性,所以将源代码和程序运行后输出的信息统一释放出来供大家参考。

-------------------------------------------------------------------------zero_array.c start------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <strings.h>

struct test {

int num;

char zero_array[];

};

#define NUM 255

#define MACRO_FREE

//#define MACRO_FREE_PAGE

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

{

struct test *tst = NULL;

int number = NUM;

tst = (struct test *)malloc(sizeof(struct test) + number);

tst->num = number;

tst->zero_array[0] = 'H';

tst->zero_array[1] = 'e';

tst->zero_array[2] = 'l';

tst->zero_array[3] = 'l';

tst->zero_array[4] = 'o';

tst->zero_array[5] = '\0';

printf("size = %ld\n", sizeof(struct test));

printf("tst->num = %d\n", tst->num);

printf("tst->zero_array[]:%s\n", tst->zero_array);

#if defined(MACRO_FREE)

free(tst);

#if defined(MACRO_FREE_PAGE)

free(tst->zero_array);

#endif

#else

;

#endif

printf("tst Addr: %p\n", tst);

printf("tst->num Addr:
%p\n", &tst->num);

printf("tst->zero_array[] Addr: %p\n", tst->zero_array);

printf("tst->zero_array[0] Addr: %p\n", &tst->zero_array[0]);

printf("tst->zero_array[1] Addr: %p\n", &tst->zero_array[1]);

return 0;

}

-------------------------------------------------------------------------zero_array.c end------------------------------------------------------------------------

-----------------------------------------------------------------------------log.tex start --------------------------------------------------------------------------

fanyanlai@ubuntu-virtual-machine:~/work/test$ ./zero_array

size = 4

tst->num = 255

tst->zero_array[]:Hello

tst Addr: 0x10dd010

tst->num Addr: 0x10dd010

tst->zero_array[] Addr: 0x10dd014

tst->zero_array[0] Addr: 0x10dd014

tst->zero_array[1] Addr: 0x10dd015

打开宏//#define MACRO_FREE_PAGE 后程序运行结果:

fanyanlai@ubuntu-virtual-machine:~/work/test$ ./zero_array

tst->num = 255

tst->zero_array[]:Hello

*** glibc detected *** ./zero_array: free(): invalid pointer: 0x0000000001e72014 ***

======= Backtrace: =========

/lib/x86_64-linux-gnu/libc.so.6(+0x7db26)[0x7ff54bc94b26]

./zero_array[0x400643]

/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ff54bc3876d]

./zero_array[0x4004c9]

======= Memory map: ========

00400000-00401000 r-xp 00000000 08:06 19770620 /home/fanyanlai/work/test/zero_array

00600000-00601000 r--p 00000000 08:06 19770620 /home/fanyanlai/work/test/zero_array

00601000-00602000 rw-p 00001000 08:06 19770620 /home/fanyanlai/work/test/zero_array

01e72000-01e93000 rw-p 00000000 00:00 0 [heap]

7ff54ba01000-7ff54ba16000 r-xp 00000000 08:06 17043068 /lib/x86_64-linux-gnu/libgcc_s.so.1

7ff54ba16000-7ff54bc15000 ---p 00015000 08:06 17043068 /lib/x86_64-linux-gnu/libgcc_s.so.1

7ff54bc15000-7ff54bc16000 r--p 00014000 08:06 17043068 /lib/x86_64-linux-gnu/libgcc_s.so.1

7ff54bc16000-7ff54bc17000 rw-p 00015000 08:06 17043068 /lib/x86_64-linux-gnu/libgcc_s.so.1

7ff54bc17000-7ff54bdcb000 r-xp 00000000 08:06 17039495 /lib/x86_64-linux-gnu/libc-2.15.so

7ff54bdcb000-7ff54bfca000 ---p 001b4000 08:06 17039495 /lib/x86_64-linux-gnu/libc-2.15.so

7ff54bfca000-7ff54bfce000 r--p 001b3000 08:06 17039495 /lib/x86_64-linux-gnu/libc-2.15.so

7ff54bfce000-7ff54bfd0000 rw-p 001b7000 08:06 17039495 /lib/x86_64-linux-gnu/libc-2.15.so

7ff54bfd0000-7ff54bfd5000 rw-p 00000000 00:00 0

7ff54bfd5000-7ff54bff7000 r-xp 00000000 08:06 17039488 /lib/x86_64-linux-gnu/ld-2.15.so

7ff54c1d9000-7ff54c1dc000 rw-p 00000000 00:00 0

7ff54c1f3000-7ff54c1f7000 rw-p 00000000 00:00 0

7ff54c1f7000-7ff54c1f8000 r--p 00022000 08:06 17039488 /lib/x86_64-linux-gnu/ld-2.15.so

7ff54c1f8000-7ff54c1fa000 rw-p 00023000 08:06 17039488 /lib/x86_64-linux-gnu/ld-2.15.so

7fff509b9000-7fff509da000 rw-p 00000000 00:00 0 [stack]

7fff509ff000-7fff50a00000 r-xp 00000000 00:00 0 [vdso]

ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

Aborted (core dumped)

-----------------------------------------------------------------------------log.tex end-----------------------------------------------------------------------------

一、零长数组优点?

1)节省空间

如果指定数组大小,当定义包含数组元素的结构体变量时,系统不但会为结构体中其它变量分配内存,同时

也会为该数组分配内存。

如果不指定数组大小(零长数组),当定义包含数组元素的结构体变量时,系统只会为结构体中其它变量分配内存,不会

为零长数组分配内存。

如代码所示:printf("size = %ld\n", sizeof(struct test));

运行程序,输出信息中:size = 4;//表明零长数组不占内存,4字节恰好为int类型变量所占内存大小。

2)灵活性

根据需要动态分配该数组长度(动态内存长度)。

如代码所示,tst = (struct test *)malloc(sizeof(struct test) + number);//为零长数组分配255字节内存。

紧接着初始化内存:

tst->zero_array[0] = 'H';

tst->zero_array[1] = 'e';

tst->zero_array[2] = 'l';

tst->zero_array[3] = 'l';

tst->zero_array[4] = 'o';

tst->zero_array[5] = '\0';

输出字符串:

printf("tst->zero_array[]:%s\n", tst->zero_array);

运行程序:

tst->zero_array[]:Hello

二、malloc动态分配内存

查看动态分配内存后结构体变量及其内部元素内部分配情况:

如代码所示:

printf("tst Addr: %p\n", tst);

printf("tst->num Addr:
%p\n", &tst->num);

printf("tst->zero_array[] Addr: %p\n", tst->zero_array);

printf("tst->zero_array[0] Addr: %p\n", &tst->zero_array[0]);

printf("tst->zero_array[1] Addr: %p\n", &tst->zero_array[1]);

运行程序:

tst Addr: 0x10dd010

tst->num Addr:
0x10dd010

tst->zero_array[] Addr: 0x10dd014

tst->zero_array[0] Addr: 0x10dd014

tst->zero_array[1] Addr: 0x10dd015

分析:零长数组与num元素刚好相差4个字节。

三、free释放内存

动态分配的内存,在用完之后,需要用free显示释放,以免造成内存泄露。

将代码中//#define MACRO_FREE_PAGE 宏打开。

运行程序:

fanyanlai@ubuntu-virtual-machine:~/work/test$ ./zero_array

tst->num = 255

tst->zero_array[]:Hello

*** glibc detected *** ./zero_array: free(): invalid pointer: 0x0000000001e72014

***

======= Backtrace: =========

/lib/x86_64-linux-gnu/libc.so.6(+0x7db26)[0x7ff54bc94b26]

./zero_array[0x400643]

/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ff54bc3876d]

./zero_array[0x4004c9]

Aborted (core dumped)

出现invalid pointer错误,说明释放动态内存成功。

注意:对于动态malloc(kmalloc)分配内存,需要用free(kfree)释放,养成编程好习惯。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: