C 语言变长数组 struct 中 char data[0] 的用法

1、结构体内存布局(padding)

为了让CPU能够更舒服地访问到变量,struct中的各成员变量的存储地址有一套对齐的机制。这个机制概括起来有两点:第一,每个成员变量的首地址,必须是它的类型的对齐值的整数倍,如果不满足,它与前一个成员变量之间要填充(padding)一些无意义的字节来满足;第二,整个struct的大小,必须是该struct中所有成员的类型中对齐值最大者的整数倍,如果不满足,在最后一个成员后面填充。

The following typical alignments are valid for compilers from MicrosoftBorland,
and GNU when compiling for 32-bit x86:

  • A char (one byte) will be 1-byte aligned.
  • A short (two bytes) will be 2-byte aligned.
  • An int (four bytes) will be 4-byte aligned.
  • A float (four bytes) will be 4-byte aligned.
  • A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux.
  • A long double (twelve bytes) will be 4-byte aligned on Linux.
  • Any pointer (four bytes) will be 4-byte aligned on Linux. (eg: char*, int*)

The only notable difference in alignment for a 64-bit linux system when compared to a 32 bit is:

  • A double (eight bytes) will be 8-byte aligned.
  • A long double (Sixteen bytes) will be 16-byte aligned.
  • Any pointer (eight bytes) will be 8-byte aligned.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

  struct s1
        {
                char ch,*ptr;
                union
                {
                        short a,b;
                        unsigned int c:2,d:1;
                };
                struct s1 *next;
        };

int main()
{

        printf("%d\n",sizeof(struct s1));
        return 0;
}

struct s1

{

char ch,*ptr;    //ch和*ptr各占2bit,共4bit

union   //按照最长的计算,union占4bit

{

short a,b;

unsigned int c:2,d:1;

}

struct *next;  //指向struct的指针,和struct占相同的字节,8bit

}

2、变长数组

摘要:在实际的编程中,我们经常需要使用变长数组,但是C语言并不支持变长的数组。此时,我们可以使用结构体的方法实现C语言变长数组。

struct
MyData

{

 int
nLen;

 char
data[0];

};

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

实际用时采取这样:

struct MyData *p = (struct MyData *)malloc(sizeof(struct MyData )+strlen(str))

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

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

程序实例:

struct MyData

{

 int nLen;

 char data[0];

};

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

以下是摘自:http://bbs.chinaunix.net/thread-1455677-1-1.html

我想举一个自己最近在项目中犯的错误来说明要踏踏实实做人,不要做装B青年 

在代码中,我需要在一个library和一个daemon之间通过socket传送数据包,包的格式定义如下(为了简化,我就用最简单的数据类型举例):

  1. typedef struct {
  2. int head;
  3. int size; //指明整个包的长度
  4. char reply;
  5. char data[0];
  6. } packet;
  7. packet*  cmd = malloc (sizeof(packet) + 20);
  8. memcpy (packet->data, some_data, 20);

复制代码

daemon将上面分配的cmd包发送给library,library接收到包后,需要将data字段中的数据取出来。size指明了整个包的长度,但没有字段指明数据的长度。我需要这么一个指明数据长度的字段吗?作为一个装B青年,我认为当然不需要,于是我这样来计算数据的长度:

  1. #define offsetof(type, element) ((int)&((type *)0)->element)
  2. static inline size_t packet_data_len(packet* cmd) {
  3. assert(cmd);
  4. return cmd->size - offsetof(packet, data);
  5. }
  6. memcpy (buffer_to_receive_data, cmd->data, packet_data_len (cmd));

复制代码

于是乎,这段程序成功的给我带来了无数的bug,莫名奇妙的segfault,奇怪的数据错误,还是有部分时间的正常工作。当然,最终我还是找到了问题:

sizeof (packet) == 12;

这是合理的,char reply被padding成了4个字节,而char data[0]字节为0。

但,offsetof(packet, data) == 9,在计算偏移时,char reply为一个字节,没有padding。

所以packet_data_len每次都会返回比真实的数据多3个字节 ……

最后我还是老老实实加了个data_len字段指明数据的长度。

时间: 2024-10-24 20:43:40

C 语言变长数组 struct 中 char data[0] 的用法的相关文章

C语言变长数组 struct中char data[0]的用法

版权声明:本文为博主原创文章,未经博主允许不得转载. [cpp] view plain copy print? 今天在看一段代码时出现了用结构体实现变长数组的写法,一开始因为忘记了这种技术,所以老觉得作者的源码有误,最后经过我深思之后,终于想起以前看过的用struct实现变长数组的技术.下面是我在网上找到的一篇讲解很清楚的文章. 在实际的编程中,我们经常需要使用变长数组,但是C语言并不支持变长的数组.此时,我们可以使用结构体的方法实现C语言变长数组. struct MyData { int nL

C语言变长数组data[0]

转载:http://www.cnblogs.com/Anker/p/3744127.html 1.前言 今天在看代码中遇到一个结构中包含char data[0],第一次见到时感觉很奇怪,数组的长度怎么可以为零呢?于是上网搜索一下这样的用法的目的,发现在linux内核中,结构体中经常用到 data[0].这样设计的目的是让数组长度是可变的,根据需要进行分配.方便操作,节省空间. 2.data[0]结构 经常遇到的结构形状如下: struct buffer { int data_len; //长度

c语言变长数组

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <time.h> #include <unistd.h> typedef struct score_s{ char name[20]; int scores[0]; }score; int main() { score *scoreInfo = malloc(

c语言,变长数组

C语言变长数组data[0][总结]: char data[0]用法总结:

变长数组(variable-length array,VLA)

处理二维数组的函数有一处可能不太容易理解,数组的行可以在函数调用的时候传递,但是数组的列却只能被预置在函数内部.例如下面这样的定义: 1 #define COLS 4 2 int sum3d(int ar[][COLS], int rows) 3 { 4 int r, c, tot; 5 tot = 0; 6 7 for(r = 0; r < rows; r++) 8 for(c = 0; c < COLS; c++) 9 tot += ar[r][c]; 10 return tot; 11

C语言中变长数组的使用方法

先说说我的理解: struct example{ __u16 tag_type; __u16 tag_len; char tag_data[0]; } __attribute ((packed)); 1. 存在的意义:当结构体的长度变长时,例如里面有一个字符串时,为了方便管理内存. 这个结构体不要用struct example a的方式定义, 而应用struct example *a; a = (struct example *)malloc(sizeof(struct example) + e

C++内存分配及变长数组的动态分配

//------------------------------------------------------------------------------------------------ 第一部分 C++内存分配 //------------------------------------------------------------------------------------------------ 一.关于内存 1.内存分配方式 内存分配方式有三种: (1)从静态存储区域分配

C之变长数组

变长数组是C99标准新加入的一个特性,它的加入大大方便了我们的编程,所谓变长数组,不是数组的长度可变,而是指允许使用变量来定义数组.这可以使我们写出更具通用性的函数.下面是一个例子,函数sum2d完成将一个二位数组中的所有数值相加并返回其和. #include<stdio.h> #define SIZE 10 #define LOC 2 #define ROW 4int sum2d(int loc, int row, int num[loc][row]); int main(void){ in

C99新增内容之变长数组(VLA)

我们在使用多维数组是有一点,任何情况下只能省略第一维的长度.比如在函数中要传一个数组时,数组的行可以在函数调用时传递,当属数组的列却只能在能被预置在函数内部.看下面一个例子: #define COLS 4 int sum2d(int ar[][COLS],int rows) { int r; int c; int tot=0; for(r=0;r<rows;r++) for(c=0;c<COLS;c++) tot+=ar[r][c]; return tot; } 现在假设定义了如下数组: in