当前位置: 首页 > wzjs >正文

有建站模板如何建设网站怎么做网站卖产品

有建站模板如何建设网站,怎么做网站卖产品,中国建设银行官网站下载,济南网站的优化1、结构体的对齐访问 1.1、通过示例理解结构体对齐是什么&#xff1f; (1)结构体中元素的内存对齐示例&#xff1a; #include <stdio.h>// 定义一个包含不同数据类型成员的结构体 struct MyStruct {char a; // 1 字节对齐int b; // 4 字节对齐short c; //…

1、结构体的对齐访问

1.1、通过示例理解结构体对齐是什么?

(1)结构体中元素的内存对齐示例:

#include <stdio.h>// 定义一个包含不同数据类型成员的结构体
struct MyStruct
{char a;     // 1 字节对齐int b;      // 4 字节对齐short c;    // 2 字节对齐char d;     // 1 字节对齐
};int main()
{printf("Size of struct MyStruct: %d bytes\r\n", (int)sizeof(struct MyStruct));  struct MyStruct s;// 输出结构体中各成员的地址,观察其对齐情况printf("Address of a: %p\n", &s.a);printf("Address of b: %p\n", &s.b);printf("Address of c: %p\n", &s.c);printf("Address of d: %p\n", &s.d);return 0;
}

执行结果:

Size of struct MyStruct: 12 bytes
Address of a: 000000000061FE14
Address of b: 000000000061FE18
Address of c: 000000000061FE1C
Address of d: 000000000061FE1E

(2)示例说明

  • 结构体 MyStruct 包含了不同数据类型成员,它们具有不同的对齐要求。char 类型通常为 1 字节对齐,int 类型一般为 4 字节对齐,short 类型一般为 2 字节对齐。
  • 当编译器为结构体分配内存时,会按照一定的规则(通常是基于系统架构和编译器的对齐策略)进行对齐。
    • 例如,在大部分常见的系统中,成员 a 占用 1 字节,之后为了满足 int 类型 4 字节对齐的要求,编译器会在 ab 之间插入 3 个字节的填充,使得 b 的地址满足 4 字节对齐的条件。
    • 同样地,b 占用 4 字节后,c 需要满足 2 字节对齐,此时如果 b 结束的地址没有满足 2 字节对齐,编译器会在 bc 之间插入填充字节。
    • 最后,d 后面也可能会根据整个结构体对齐要求进行填充,以确保结构体的整体大小满足最大成员对齐要求,示例中整个结构体的大小可能大于各成员大小之和,这是因为填充字节的存在。

1.2、结构体为什么需要内存对齐

(1)结构体中元素对齐访问主要原因是为了配合硬件,也就是说硬件本身有物理上的限制,如果对齐访问会提高效率,否则会大大降低效率。

(2)对比对齐访问和不对齐访问:对齐访问牺牲了内存空间,换取了速度性能;而非对齐访问牺牲了访问速度性能,换取了内存空间的完全利用。

1.3、结构体对齐的规则

(1)编译器本身可以设置内存对齐的规则,在32位芯片的编译器中,一般编译器默认对齐方式是4字节对齐。

(2)结构体对齐的关键,编译器为4字节对齐时:

  • 结构体整体本身起始位置在4字节对齐处,结构体对齐后的大小必须4的倍数。
  • 结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。
    • char是1字节对齐
    • short是2字节对齐
    • int是4字节对齐
    • float是4字节对齐
    • double是8字节对齐
  • 不同数据类型的对齐字节数不同:
    • 因为对齐地址可以把相邻的4字节中的数据一次性取出,从而提高访问效率。
    • double 在 32 位编译器中是 8 字节对齐,这主要是为了内存访问效率和浮点运算单元的要求,而非仅仅因为 32 位处理器一次读取 4 字节。
  • 编译器考虑结构体存放时,以满足以上要求的最少内存需要来排布元素。

1.4、gcc支持但不推荐的对齐指令

(1)对齐指令:   

  • #pragma pack(n) :从当前位置开始,将当前文件的对齐方式设置为n字节对齐,n的常见取值为 1、2、4、8 等。
  • #pragma pack(): 将对齐方式恢复到编译器的默认对齐方式 。

(2)示例代码,设置1字节对齐:

#include <stdio.h>#pragma pack(1)
// 定义一个包含不同数据类型成员的结构体
struct MyStruct
{char a;     // 1 字节int b;      // 4 字节short c;    // 2 字节char d;     // 1 字节
};
#pragma pack()int main()
{// Size of struct MyStruct: 8 bytesprintf("Size of struct MyStruct: %d bytes\r\n", (int)sizeof(struct MyStruct));return 0;
}

(3)#pragma是用来指挥编译器,或者说设置编译器的对齐方式的。编译器的默认对齐方式是4,但是有时候我不希望对齐方式是4,而希望是别的(譬如希望1字节对齐,也可能希望是8,甚至可能希望128字节对齐)。

(4)我们需要#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐字节数就是n。

(5)#prgma pack的方式在很多C环境下都是支持的,但是gcc虽然也可以不过不建议使用。

1.5、gcc推荐的对齐指令

(1)对齐指令:

  • __attribute((packed)) / __attribute__((packed))  
    • 设置为1字节对齐。
    • 指定该数据类型(通常是结构体或联合体)的成员以最紧凑的方式存储,即每个成员紧跟在前一个成员之后,不进行任何填充对齐,从而可以尽可能地节省内存空间。
    • 作用的范围只有加了这个东西的这一个类型。
    • __attribute((packed))__attribute__((packed)) 在功能上是相同的,现代代码中通常使用__attribute__((packed))这种写法,因为它更符合规范。
    • 作用于变量无效。
  • __attribute__((aligned(n)))
    • 用于指定变量、结构体或类型的内存对齐方式。
    • __attribute__((aligned(n)))作用于结构体时,作用是让整个结构体变量整体进行n字节对齐,而不是结构体内各元素也要n字节对齐。
    • 既可以作用于类型,也可作用于变量。
      char c __attribute__((aligned(4))); // 指定变量 c 按 4 字节对齐

(2)__attribute__((packed))使用示例:

#include <stdio.h>// 定义一个包含不同数据类型成员的结构体
struct MyStruct1
{char a;     // 1 字节int b;      // 4 字节short c;    // 2 字节char d;     // 1 字节
}__attribute__((packed));struct __attribute__((packed)) MyStruct2
{char a;     // 1 字节int b;      // 4 字节short c;    // 2 字节char d;     // 1 字节
};int main()
{// Size of struct MyStruct1: 8 bytesprintf("Size of struct MyStruct1: %d bytes\r\n", (int)sizeof(struct MyStruct1));// Size of struct MyStruct1: 8 bytesprintf("Size of struct MyStruct2: %d bytes\r\n", (int)sizeof(struct MyStruct2));return 0;
}

2、offsetof宏与container_of宏

2.1、offsetof宏

(1)offsetof宏的作用是:用宏来计算结构体中某个元素和结构体首地址的偏移量,其实质是通过编译器来计算的。

(2)使用示例:

#include <stdio.h>struct mystruct
{char a;int b;short c;
};// offsetof宏的原理:TYPE为结构体类型,MEMBER为结构体元素
// ((TYPE *)0): 虚拟一个type类型结构体指针,指向首地址为0的结构体变量。
// 实际上这个结构体变量可能不存在,但是只要我不去解引用这个指针就不会出错。// ((TYPE *)0)->MEMBER:然后用->的方式来访问结构体元素;
// &((TYPE *)0)->MEMBER):再然后通过取地址符获得结构体元素的地址;// 因为虚拟的结构体指针变量指向的结构体的首地址为0,
// 所以获得的 结构体元素的地址 就等效为 结构体元素相对于整个结构体变量首地址的偏移量。
#define offsetof(TYPE, MEMBER)    ((int)&((TYPE *)0)->MEMBER)int main(void)
{struct mystruct s1;s1.b =12;// 手工计算结构体元素b的地址int *p1 = (int *)((char *)&s1 + 4);printf("*p1 = %d.\n", *p1);// 通过offsetof宏计算元素b的地址int *p2 = (int *)((int)&s1 + offsetof(struct mystruct, b));printf("*p2 = %d.\n", *p2);// 计算结构体元素相对于整个结构体变量首地址的偏移量int offsetof_a = offsetof(struct mystruct, a);printf("offsetof_a = %d.\n", offsetof_a);int offsetof_b = offsetof(struct mystruct, b);printf("offsetof_b = %d.\n", offsetof_b);int offsetof_c = offsetof(struct mystruct, c);printf("offsetof_c = %d.\n", offsetof_c);return 0;
}

2.2、container_of宏

(1)作用:知道一个结构体中某个元素的指针,反推这个结构体变量的指针。

(2)有了container_of宏,我们可以从一个元素的指针得到整个结构体变量的指针,继而得到结构体中其他元素的指针。

(3)typeof关键字的作用是:由变量名得到变量的数据类型。

int a;  typeof(a)  b;      // 定义了一个和a数据类型相同的变量b。

(4)使用示例

#include <stdio.h>struct mystruct
{char a;int b;short c;
};// 宏说明: TYPE是结构体类型,MEMBER是结构体中一个元素的元素名;
// 宏返回的是MEMBER元素相对于整个结构体变量的首地址的偏移量,类型是int.
#define offsetof(TYPE, MEMBER)    ((int)&((TYPE *)0)->MEMBER)// 宏说明:ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名;
// 宏返回的就是指向结构体变量的指针,类型是(type *).
#define container_of(ptr, type, member)  ({                \const typeof(((type *)0)->member) * __mptr = (ptr);    \(type *)((char *)__mptr - offsetof(type, member));  })int main(void)
{struct mystruct s1;struct mystruct *pS = NULL;short *p = &s1.c;                 // 指向结构体中成员c的指针// 一般情况获取结构体变量的地址printf("s1的地址等于:%p.\n", &s1);// 已知结构体成员的指针,计算结构体变量的指针。pS = container_of(p, struct mystruct, c);printf("pS等于:%p.\n", pS);return 0;
}

(5)宏原理说明:

// 宏说明: TYPE是结构体类型,MEMBER是结构体中一个元素的元素名;
// 宏返回的是MEMBER元素相对于整个结构体变量的首地址的偏移量,类型是int.
#define offsetof(TYPE, MEMBER)    ((int)&((TYPE *)0)->MEMBER)// 宏说明:ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名;
// 宏返回的就是指向结构体变量的指针,类型是(type *).
#define container_of(ptr, type, member)  ({                \const typeof(((type *)0)->member) * __mptr = (ptr);    \(type *)((char *)__mptr - offsetof(type, member));  })
  • ((type *)0): 虚拟一个type类型结构体指针,指向首地址为0的结构体变量。
  • (((type *)0)->member): 通过->访问结构体成员member。
  • typeof(((type *)0)->member): 通过tyeof得到结构体成员member的数据类型。
  • const typeof(((type *)0)->member) * __mptr: 定义指向member类型的指针变量__member。const表示指针指向的内容不能被修改,因为是虚拟的结构体变量,解引用会内存非法访问。
  • const typeof(((type *)0)->member) * __mptr = (ptr);  :结构体成员变量指针赋值。
  • (type *)((char *)__mptr - offsetof(type, member));  :结构体成员变量的地址 减去 该成员相对于整个结构体变量的首地址的偏移量,得到结构体的地址。
http://www.dtcms.com/wzjs/227273.html

相关文章:

  • 网站域名查询ip中国职业培训在线
  • 物业公司网站模板网络营销的特征和功能
  • 七牛云wordpress图片北京搜索优化推广公司
  • 劫持网站挂广告是个人做的吗基本seo
  • 郑州华久做网站淄博网站seo
  • 河北沧州做网站的电话网站统计
  • 阜城网站建设价格百度刷自己网站的关键词
  • 区块链网站开发沈阳网站制作优化推广
  • wordpress 防篡改惠州百度关键词优化
  • 上海网站营销是什么宁波seo自然优化技术
  • 河南营销网站建设联系方式国内真正的永久免费建站
  • WordPress 蜘蛛检测深圳优化公司找高粱seo服务
  • 网站的分辨率是多少龙泉驿网站seo
  • 单页面网站制作技术网络推广公司电话
  • php学校网站系统最近一周新闻大事件
  • 普陀手机网站建设微信引流被加软件
  • 网站首页在哪个文件夹怎么做私人网站
  • 郑州网站建设设计公司哪家好网站推广是干嘛的
  • 西安做网站的公司seo基础知识
  • 河南省建设监理网站东莞seo网站制作报价
  • wordpress 主题制作教程武汉seo诊断
  • 桐城市做网站全渠道营销
  • 开游戏公司需要多少钱seo收录查询工具
  • 网站开发的交付文档windows优化软件排行
  • 网站服务器出问题海南百度推广运营中心
  • 全国企业信用信息公开系统重庆seo网络推广关键词
  • 首页>新闻>正文 网站怎么做做网站比较好的公司有哪些
  • 党的建设信息网站台州关键词首页优化
  • 网页考试题及答案seo优化服务是什么
  • 汕头网站建设设计公司seo推广绩效考核指标是什么