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

wordpress添加一个tag页面seo 网站

wordpress添加一个tag页面,seo 网站,wordpress自定义字段图文,内蒙古赤峰市建设局网站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/579072.html

相关文章:

  • 企业网站搭建哪家好wordpress主页不显示
  • 网站还能赚钱吗广告牌模板图片
  • 网站的商桥怎么做网站建设捌金手指花总二
  • 手机网站建设cz35短链接生成算法
  • 传统企业网站建设制作海珠营销型网站建设
  • 网站做支付接口吗广东网站建设公司有哪些
  • 网站收录在哪里可以查看肇庆 网站建设公司有哪些
  • 郴州做网站seo门户网站的流程
  • 自己怎么做入网站回收书报网站开发适合什么工作
  • 福鼎网站建设培训网站建设技术工具
  • 建站吗官方网站马云做网站最开始怎么盈利的
  • 商务卫士包括网站建设济南10大互联网公司排名
  • 微商网站建设做钢材都有什么网站
  • 网站推广策划书网站空间年费
  • 如何让网站互动起来医院网站建设案例
  • 域名访问不了织梦网站网站建设 图书
  • 哪个网站是做韩国化妆品正品个人备案可以做影视网站吗
  • 手机网站一年维护费个人网站费用
  • 做服装有哪些好的网站有哪些惠州市住房和城乡规划建设局官方网站
  • 做百度竞价网站搜索不到wordpress自动添加关键字
  • 有后台的网站字体设计灵感网站
  • 下载正品官方网站郑州网站制作设计
  • 建设电子书阅读网站上海seo培训中心
  • 盘锦网站建设服务石家庄响应式模板建站
  • 北京微信网站开发报价效果图网站建设
  • 百度网站优化推广网站美工建设软件下载
  • 网站做优化需要多少钱聊城网站制作工作室
  • 免费自助建站自助建站平台asp.net网站伪静态
  • 网站开发交付资料金融网站制作
  • 网站图标 代码优质的网站自助建站