变长结构体_结构体中byte类型数据的长度会变化? - CSDN
精华内容
参与话题
  • c语言变长结构体

    千次阅读 2017-08-27 15:48:37
    1.什么是变长数组 struct MyData { int nLen; char data[0]; }; sizeof(MyData)=4; 可能有的编译器不支持char data[0];需要用char data[1];代替,这样上面结构体大小是sizeof(MyData)=8(字节对齐); 在上...

         1.什么是变长数组

    struct MyData 
    {
        int nLen;
        char data[0];
    };   
    	sizeof(MyData)=4;

    可能有的编译器不支持char data[0];需要用char data[1];代替,这样上面结构体大小是sizeof(MyData)=8(字节对齐);

    在上结构中,data是一个数组名;但该数组没有元素;该数组的真实地址紧随结构体MyData之后,而这个地址就是结构体后面数据的地址(如果给这个结构体分配的内容大于这个结构体实际大小,后面多余的部分就是这个data的内容),这种声明方法可以巧妙的实现C语言里的数组扩展

    如下下所示:

    #include <iostream>
    using namespace std;
    struct MyData 
    {
        int nLen;
        char data[0];			//如果这里用char* data;代替呢?是一个指针占用空间,而采用变长数组不占内存,数组名只是一个符号
    							//代表一个不可修改的地址常量
    };
    
    int main()
    {
        int nLen = 10;
        char str[10] = "123456789";
    
        cout << "Size of MyData: " << sizeof(MyData) << endl;
    
        MyData *myData = (MyData*)malloc(sizeof(MyData) + 10);
        memcpy(myData->data,  str, 10);
    
        cout << "myData's Data is: " << myData->data << endl;
    
        free(myData);
    
        return 0;
    }
    
    
    //输出:
    Size of MyData: 4
    myData's Data is: 123456789   
    //由于数组没有元素,该数组在该结构体中不分配占用空间,所以sizeof(struct Mydata) = 4。 

    实际用时采取这样:
             struct MyData *p = (struct MyData *)malloc(sizeof(struct MyData )+strlen(str))

    这样就可以通过p->data 来操作这个str。


    struct MyData1 
    {
        int nLen;
        char data[0]; //char data[1];有的编译要求这样写

    };

    struct MyData2 
    {
        int nLen;
        char*data;

    };

    对于上面两个结构体有下面几点说明:
    1. MyData1  (char data[0])结构体占用内存最小,Mydata2有个指针占用4B
    2.MyData1与前面结构体数据是连续的内存存储空间,而MyData2下,新增加数据data是单独开辟的空间;
    3.释放内存时,MyData1可以直接释放,而MyData2需要先释放指针指向内存,然后再释放结构体数据部分否则会内存泄漏



    展开全文
  • 深入浅出变长结构体

    万次阅读 多人点赞 2013-11-03 11:13:56
    深入浅出变长结构体 1、 问题的引出  项目中用到数据包的处理,但包的大小是不固定的,其长度由包头的2字节决定。比如如下的包头:88 0f 0a ob cd ef 23 00 。长度由头2个字节880f决定,考虑字节序,转为0f88,转为...

    深入浅出变长结构体

    1、 问题的引出

            项目中用到数据包的处理,但包的大小是不固定的,其长度由包头的2字节决定。比如如下的包头:88 0f 0a ob cd ef 23 00 。长度由头2个字节880f决定,考虑字节序,转为0f88,转为10进制3976个字节的包长度。

            这个时候存储包的时候,一方面可以考虑设定包的大小固定:如4K=4*1024=4096个字节,因为最大包长不可能超过4k,但该方法的有缺陷,存在一种极端就是包最小仅含包头不含数据域,此时包为8个字节,浪费了4096-8 =4088个字节的存储空间。另一方面考虑有没有一种方法能根据长度进行存储,或者说初始不分配长度,计算出了长度后再分配存储呢。而实际项目中正是通过包头计算出了包的整体大小的。

            这就引出了变长结构体的概念。

     

    2、 什么叫变长结构体?

         如下所示:

    struct Var_Len_Struct
    {
         int nsize;
         char buffer[0];
    };


            那结构体是怎么实现可变长的呢?如上所示,请注意看结构体中的最后一个元素,一个没有元素的数组。我们可以通过动态开辟一个比结构体大的空间,然后让buffer去指向那些额外的空间,这样就可以实现可变长的结构体了。更为巧妙的是,我们甚至可以nsize存储字符串buffer的长度

           并且,上述的结构体可以扩展,比如笔者项目中遇到的存储数据包,前面可能类似包头的部分(存储类型、长度等信息),而后面buffer则存储数据部分。

           同时,需要引起注意的:ISO/IEC 9899-1999里面,这么写是非法的,这个仅仅是GNU C的扩展,gcc可以允许这一语法现象的存在。但最新的C/C++不知道是否可以,我没有测试过。C99允许。

     

    3、变长结构体的好处体现在哪?

            可能有的同学会问到,1引出部分如果说定义定长数组浪费空间,定义一个指针不也能指向变长的数据域部分吗?

           是的,是可以实现的。那么我们就对比下有什么不同。

           结构体1:s_one,用指针指向数据域部分;

           结构体2:s_two, 用[0]的数组;

           结构体3:s_three, 因为有的编译器不支持[0],我们用[1]来表示;多了些存储。

     

    #include <stdafx.h>
    #include <iostream>
    using namespace std;
     
    const int BUF_SIZE = 100;
     
    struct s_one
    {
    ints_one_cnt;
    char*s_one_buf;
    };
     
    struct s_two
    {
    ints_two_cnt;
    chars_two_buf[0];
    };
     
    struct s_three
    {
    ints_three_cnt;
    chars_three_buf[1];
    };
     
    int main()
    {
    //赋值用
    constchar* tmp_buf = "abcdefghijklmnopqrstuvwxyz";
    intntmp_buf_size = strlen(tmp_buf);
     
    //<1>注意s_one 与s_two的大小的不同
    cout<< "sizeof(s_one) = " << sizeof(s_one) << endl; //8
    cout<< "sizeof(s_two) = " << sizeof(s_two) << endl; //4
    cout<< "sizeof(s_three) = " << sizeof(s_three) << endl;//5-->8结构体对齐
    cout<< endl;
     
    //为buf分配100个字节大小的空间
    intntotal_stwo_len = sizeof(s_two) + (1 + ntmp_buf_size) * sizeof(char);
    intntotal_sthree_len = sizeof(s_three) + ntmp_buf_size * sizeof(char);
     
    //给s_one buf赋值
    s_one*p_sone = (s_one*)malloc(sizeof(s_one));
    memset(p_sone,0, sizeof(s_one));
    p_sone->s_one_buf= (char*)malloc(1 + ntmp_buf_size);
    memset(p_sone->s_one_buf,0, 1 + ntmp_buf_size);
    memcpy(p_sone->s_one_buf,tmp_buf, ntmp_buf_size);
     
    //给s_two buf赋值
    s_two*p_stwo = (s_two*)malloc(ntotal_stwo_len);
    memset(p_stwo,0, ntotal_stwo_len);
    memcpy((char*)(p_stwo->s_two_buf),tmp_buf, ntmp_buf_size);  //不用加偏移量,直接拷贝!
     
    //给s_three_buf赋值
    s_three*p_sthree = (s_three*)malloc(ntotal_sthree_len);
    memset(p_sthree,0, ntotal_sthree_len);
    memcpy((char*)(p_sthree->s_three_buf),tmp_buf, ntmp_buf_size);
     
    cout<< "p_sone->s_one_buf = " << p_sone->s_one_buf<< endl;
    cout<< "p_stwo->s_two_buf = " << p_stwo->s_two_buf<< endl;
    cout<< "p_sthree->s_three_buf = " <<p_sthree->s_three_buf << endl; //不用加偏移量,直接拷贝!
    cout<< endl;
     
    //<2>注意s_one 与s_two释放的不同!
    if(NULL != p_sone->s_one_buf)
    {
            free(p_sone->s_one_buf);
            p_sone->s_one_buf= NULL;
     
            if(NULL != p_sone)
            {
                   free(p_sone);
                   p_sone= NULL;
            }
            cout<< "free(p_sone) successed!" << endl;
    }
     
    if(NULL != p_stwo)
    {
            free(p_stwo);
            p_stwo= NULL;
     
            cout<< "free(p_stwo) successed!" << endl;
    }
     
    if(NULL != p_sthree)
    {
            free(p_sthree);
            p_sthree= NULL;
     
            cout<< "free(p_sthree) successed!" << endl;
    }
     
    return0;
    }


     

           笔者vc6.0的编译器会有如下的警告:

     

           运行结果如下:

           对比结果,我们能发现:

           <1> 存储大小方面:s_two的存储较s_one、s_three都要少,[0]的好处,即用指针的方式需要多开辟存储空间的。

           <2> 数据连续存储方面:s_one明显数据域是单独开辟的空间,与前的nsize不在连续的存储区域,而s_two,s_three则在连续的存储空间下。

           <3>释放内存方面:显然s_one的指针的方式,需要先释放数据域部分,才能释放指向结构体的指针变量;而s_two,s_three可以直接释放。

           总结如下:

           结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)。

          而如果使用数组,那么只需要一次就可以全部分配出来,反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。

          其实变长结构体就是分配一段连续的的内存,减少内存的碎片化,简化内存的管理

     

    4、变长结构体的应用

           <1>Socket通信数据包的传输;

           <2>解析数据包,如笔者遇到的问题。

           <3>其他可以节省空间,连续存储的地方等。

     

     

           未尽事宜,后续补上……

           2013/9/22pm21:36思于家中床前

     

    作者:铭毅天下

    转载请标明出处,原文地址:http://blog.csdn.net/laoyang360/article/details/11908731

    如果感觉本文对您有帮助,请点击支持一下,您的支持是我坚持写作最大的动力,谢谢!

     

    展开全文
  • 变长结构体的应用

    千次阅读 2016-03-01 01:15:41
    顾名思义,结构体长度是“可”的。但是这个可不针对sizeof()函数。 用例代码: //弹性数组的大小,各对象是否都不一样? //如果都一样,怎么看空间大小,用sizeof array来加? //但是如果是对象,也没法看,...

    顾名思义,结构体长度是“可变”的。但是这个可变不针对sizeof()函数。


    用例代码:

    //弹性数组的大小,各对象是否都不一样?
    //如果都一样,怎么看空间大小,用sizeof array来加?
    //但是如果是对象,也没法看,因为是指针指向对象的形式
    //用的时候,申请可以是这样
    #include<malloc.h>
    #define ARRAY_SIZE 200
    struct S{
    int* a;
    int *b;
    char array[0];
    };
    struct S2{
    int* a;
    int *b;
    char array[];//另一种更稳妥的形式,而前者可能编译报错
    };
    struct S3{
    int a;
    char *array;
    };
    
    int main(){
            struct S* p = (struct S*)malloc(100);
            strcpy(p->array,"hello");
            printf("struct's size %d\n",sizeof(struct S));
            printf("strict pointer's size:%d\n",sizeof(p));
            printf("sizeof array : %d\n",sizeof(p->array));
            printf("strlen array: %d\n",strlen(p->array));
            printf("%s\n",p->array);
    //用的时候,申请可以是这样
            struct S* p2 = (struct S*)malloc(sizeof(struct S) + ARRAY_SIZE);
            struct S2* pS2 = (struct S2*)malloc(sizeof(struct S2) + ARRAY_SIZE);
            strcpy(p2->array,"hello");
            printf("struct's size %d\n",sizeof(struct S2));
            printf("strict pointer's size:%d\n",sizeof(p2));
            printf("sizeof array : %d\n",sizeof(p2->array));
            printf("strlen array: %d\n",strlen(p2->array));
            printf("%s\n",p->array);
    
    
            struct S3* p3 = (struct S3*)malloc(sizeof(struct S3));
            p3->array = (char *)malloc(ARRAY_SIZE);
    
            strcpy(p3->array,"hello world");
            printf("p3->array:%s\n",p3->array);
            //free(p3->array);
            //改变顺序运行也不报错,给free传参就不算访问了?
            //p3已经free了,还能访问p3->array?
            free(p3);
            printf("p3->array:%s\n",p3->array);
            free(p3->array);
    //访问其实都能访问,就是不确保对了吧
            printf("p3->array:%s\n",p3->array);
    
    }
    


    打印输出:

    struct's size 8
    strict pointer's size:4
    sizeof array : 0
    strlen array: 5
    hello
    struct's size 8
    strict pointer's size:4
    sizeof array : 0
    strlen array: 5
    hello
    p3->array:hello world
    p3->array:hello world
    p3->array:hello world



    总结:sizeof看结构体,只有实体数据和指针占空间,char array[0]是不占长度的。

    变长结构体的0长度数组有两种声明方法(见S1和S2),不影响sizeof()对结构体大小的判断。

    变长结构体S1与S2是为了达到和S3相同的效果而生的,具体内容的访问上也有些类似。

    应用上,必须用堆空间,指针的应用也很巧妙,指向紧跟结构体数组的位置。至于后边的为什么能用,因为后边空间是malloc或new来的一大片连续空间的一部分。

    如果堆空间的申请/销毁的资源开支大与效率低是个劣势的话,可能优势就在于和S3的二次申请/销毁比,开支还会小点。这样选择也肯定是非这么用不可的时候了。比如我要接动态的数据,打包并发送,数据包的头部分肯定是固定的,但是尾部,内容具体有多长不确定,如果都以最大长度来申请,会很耗费内存。

    struct s* ps = malloc(sizeof(struct S)+strlen(string1));//比如是字符串,有了变长结构体,我就我就能strlen()一下获取长度,再去申请合适的空间

    有一个问题无解,sizeof()结构体是固定长度,sizeof()对象都是多长?因为动态申请时你只拿到了指针,所以看不到对象长度,只能看到4(32位机)。

    注意:据说,按理说也是,如果用S3,必须先释放array的空间,再释放S3结构体对象的空间。但是感觉上顺序颠倒也能行,这是因为删除数据的原则只是不再用,而不是去改变内存具体的电容存储内容,巧合罢了,但是很危险,属于越界行为。如果是动态运行,应该就会出错了(不过在另一个blog中我在linux gcc的爆堆实验没怎么成功,就是说,即使free过,也会耗尽资源,总之不能重复涂抹一处空间)


    ===========================================

    以前IM的项目里别人的代码中,有个用法,感觉是错误的,至少不是变长结构体的用法,也许是重用名的用法?创建一个别名!也许是不懂变长结构体,迭代的时候胡乱修改,成这样了。这个结构体的长度是36==16+6+6+4,0长度数组的特性还在,倒是可以实现一个成员的重命名功能,也许真是为了干这个的,不过就是提醒一下,零长度数组必须放到末尾才能起到变长结构体的效果,并且必须是动态申请的堆空间。动态申请的你只能用指针访问,所以也无从获取对象长度,所以要谨慎判断变长结构体的边界。

    // 注册
    typedef struct
    {
    	long long m_llUserId; 	// 用户名
    	char m_pcPsw[0];		// 密码
    		char ShamPsw[16];	// 忽略
    
    	char m_pcVerCode[0];		// 验证码
    		char ShamVerCode[6];	// 忽略
    		
    	char m_pcCode[0];		// 邀请码
    		char ShamCode[6];	// 忽略
    }TRegisterData;
    

    下面演示一下别名(Nickname)的用法:

    #include<stdio.h>
    #include<malloc.h>
    #define ARRAY_SIZE 200
    struct S2{
    int* a;
    int *b;
    //char arrayNickname[];//不写0的话,定义非变长结构体时编译不过去
    char arrayNickname[0];//更稳妥的写法
    char array[18];
    };
    int main(){
            struct S2* pS2 = (struct S2*)malloc(sizeof(struct S2) + ARRAY_SIZE);
            strcpy(pS2->array,"hello");
            printf("struct's size %d\n",sizeof(struct S2));
            printf("strict pointer's size:%d\n",sizeof(pS2));
            printf("sizeof arrayNickname : %d\n",sizeof(pS2->arrayNickname));
            printf("strlen arrayNickname: %d\n",strlen(pS2->arrayNickname));
            printf("array:%s\n",pS2->array);
            printf("arrayNickname:%s\n",pS2->arrayNickname);
    
    }
    

    struct's size 28
    strict pointer's size:4
    sizeof arrayNickname : 0
    strlen arrayNickname: 5
    array:hello
    arrayNickname:hello
    



    展开全文
  • C++之变长数组与变长结构体

    千次阅读 2018-03-18 20:13:31
    在C99标准中,新加入了变长数组和变长结构体变长数组如下:其中a[n]就是变长数组,b[10]就是定长数组int main() { int b[10]; int n = 10; int a[n]; }该变长数组也可以对应于malloc的动态空间分配,等价于int *...

    在C99标准中,新加入了变长数组和变长结构体

    变长数组如下:其中a[n]就是变长数组,b[10]就是定长数组
    int main() {
        int b[10];
        int n = 10;
        int a[n]; 
    }

    该变长数组也可以对应于malloc的动态空间分配,等价于

    int *a = malloc(n * sizeof(int));


    二者的区别:
    1.变长数组从栈上分配空间,malloc从堆上分配空间;

    2.栈上分配和回收空间比堆上分配和回收空间要快;
    3.当n过大时,可能导致栈溢出,但malloc分配时不会。

    变长结构体:
    变长结构体是将数组放在结构体末尾,通过给变长结构体动态分配内存时,额外分配更多的空间做buffer。值得注意的是,数组名是一个偏移量,本身不会占用空间,数组名代表的是一个不可修改的地址常量,但是我们对这个数组名指向的空间可以随意的指定。
    变长结构体分配额外的空间做buffer的例子如下:
    #include <stdio.h>
    #include <stdlib.h>
    struct v_struct { 
        int i; 
        int a[0];
    };
    
    int main() 
    { 
        v_struct *pv = (v_struct *)malloc(sizeof(v_struct)+sizeof(int)* 100); 
        pv->a[50] = 100; 
        printf("sizeof int is equal to %u\n", sizeof(int)); 
        printf("sizeof v_struct is equal to %u\n", sizeof(v_struct));
        printf("%u\n", sizeof(pv)); 
        return 0;
    }
    运行结果为,两者的大小均为4

    顺带打印了指针的大小,若机器是32寻址的,则指针大小为4字节,若机器是64位寻址的,则指针大小为8字节

    变长结构体的作用:

    1.变长结构体的变长部分通常可以用来作为buffer,缓存数据。

    2.变长结构体的空间释放是很方便的,只需要free(pv), 而且不会造成内存泄露。

    3.变长结构体使用起来更方便,不过,要小心越界。


    为何不用指针代替变长结构体?
    指针与变长结构体的区别:
    1.位置方面:指针可以放在任何地方,但是变长结构体的变长部分一定要放在结构体的尾部;

    2.内存占用方面:指针会占用一个指针大小的内存空间,但是变长数组不占内存,它只是一个占位符;
    3.内存布局方面:指针指向的内存和结构体的内存可以是不连续的,但是变长部分和结构体的内存必须是连续的。
    4.内存释放方面:使用指针,需要先释放指针所指向的内存,再释放整个结构体的内存,否则会造成内存泄漏;而使用变长结构体可以直接释放整个结构体的空间;
    5.限制方面:指针可以用在C++的类中,而变长结构体不可以。因为有些编译器会将一些额外的信息放在类的最后,比如vptr或者虚基类的内容,使用了变长的类,就会把这部分的值改变,这种行为是未定义的。

    参考博客:
    http://blog.csdn.net/SKY453589103/article/details/51147505
    展开全文
  • 解析变长结构体的用法和优点

    千次阅读 2017-05-14 10:08:06
    变长结构体:在接触变长结构体之前,以为会是一个很难理解的东西,但是这其实算是C里面的一种技巧吧,优点是:分配了一段连续的内存,防止内存碎片化以及方便内存的管理。使用变长结构体的格式如下:struct Test { .......
  • 零长度和变量长度数组GNU C 允许使用零长度数组,在定义变长对象的头结构时,这个特性在一些数据进行网络通信时非常有用。 但是零长度的数组编译环境不同会出问题,所以用下面的格式。 typedef struct package{ int...
  • 变长结构体的几种方法

    千次阅读 2009-09-30 16:48:00
    定义结构体时,往往其成员中含有变长的元素,可用以下方法解决 一、定义变长数组struct CToolBarData{ WORD wVersion; //版本号 ==1 WORD wWidth; WORD wHeight; WORD wItemCount; //给出后面有几项 WORD ...
  • C语言udp socket发送结构体

    千次阅读 2016-07-05 20:19:01
    利用udp发送数据时,...结构体和char转换有很多种方法,每种方法所使用的条件也不同,一般来说,对于定长的结构体来说比较简单,变长的结构体的转换较为复杂。 在此介绍定长结构体的转换与发送的简单方法,当然应用
  • C++ 总结几种结构体初始化的方法

    万次阅读 2017-06-05 19:00:57
    三种方法: 1、结构体的构造函数中初始化. 2、继承模板类初始化. 3、定义时初始化.
  • 结构体中的变长数组

    千次阅读 2011-05-19 16:05:00
    #include"stdio.h" #include"malloc.h" #include //int 4字节,char 1个字节 ...//变长数组 }; void main() { struct node *xiaobo1; //printf("%d",sizeof( struct node)); xiaobo1 = malloc(sizeof(stru
  • memcpy-结构体的复制

    万次阅读 2014-11-24 16:48:12
    一个memcpy的结构体的复制,类似于C++中调用类的拷贝构造函数,用一个对象去初始化另一个对象! #include "stdio.h" #include "string.h" void main(void) { struct s1 {  char *name;  int age; }stu1={...
  • C语言结构体(struct)常见使用方法

    万次阅读 多人点赞 2019-11-13 00:27:27
    基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。 (因为C++和C有共通之处,但是在...
  • linux
  • 结构体定义使用及指针长度问题

    千次阅读 2014-08-12 17:36:56
    1.结构体定义
  • C++变长结构体

    千次阅读 2018-07-04 21:23:25
    变长结构体,其实真正意义上并不是结构体的大小可变,而是使用结构体中的变量代表一个地址,从而访问超出结构体大小范围的数据如下两个结构体:using node = struct node { int a; int b; }using nodes = struct ...
  • 在本科以来,由于老师和自己的种种原因,我一直不知道结构体和Malloc是什么,每当考试的时候,尤其是数据结构和操作系统考试的时候,我就会对着诸如《【C】利用单链表数据结构实现通讯录,链表的增删改查》(点击...
  • 使struct对象拥有可大小的数组

    千次阅读 2016-12-12 10:16:43
    结构体中最后一个元素是长度为0的数组 在Linux源代码中,有很多的结构体最后都定义了一个元素个数为0个的数组,如/usr/include/linux/if_pppox.h中有这样一个结构体:  struct pppoe_tag {   __...
  • 结构体中最后成员为一个数组(长度为零)与一个指针 转自:http://blog.csdn.net/cylan_jia/article/details/7753465 1. 结构体中最后一个数组长度为零 typedef struct _ex_mng {  unsigned int type;  ...
  • C语言中的结构体(struct)

    万次阅读 多人点赞 2016-02-15 20:23:39
    C语言中,结构体类型属于一种构造类型(其他的构造类型还有:数组类型,联合类型)。本文主要介绍关于结构体以下几部分。 1、概念为什么要有结构体?因为在实际问题中,一组数据往往有很多种不同的数据类型。例如,...
  • 指向结构体的指针

    万次阅读 多人点赞 2012-12-11 17:31:24
    指向结构体的指针   在C语言中几乎可以创建指向任何类型的指针,包括用户自定义的类型。创建结构体指针是极常见的。下面是一个例子: typedef struct { char name[21]; char city[21]; ...
1 2 3 4 5 ... 20
收藏数 47,774
精华内容 19,109
关键字:

变长结构体