1.结构体变量中的元素如何访问?

(1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式);实质上都是指针方式访问。
(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来访问。(.和->访问结构体元素其实质是一样的,只是C语言规定用结构体变量来访问元素用. 用结构体变量的指针来访问元素用->。实际上在高级语言中已经不区分了,都用.)
(3)结构体的访问方式有点类似于数组下标的方式

2.利用指针访问结构体元素

  结构体元素地址=结构体首地址+元素偏移量

  

struct mystruct
{
int a;
int b; } s1; //s1.b的地址
int* p=(int*)((int)&s1+);
*p=;// s1.b=5;

3.结构体对齐

  一般情况下,为了配合硬件,如果对齐排布和访问会提高效率,否则会大大降低效率。

  (0)、一般编辑器默认4字节对齐。

  (1)、结构体对齐要考虑:结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数(编译器设置为4字节对齐时,如果编译器设置为8字节对齐,则这里的4是8)
  (2)、结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。
  (3)、编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。

struct mystruct1
{    // 1字节对齐 4字节对齐
int a;         // 4 4
char b; // 1 2(1+1)
short c;   // 2 2
}; struct mystruct11
{ // 1字节对齐 4字节对齐
int a; // 4 4
char b; // 1 2(1+1)
short c;   // 2 2
}; typedef struct mystruct111
{ // 1字节对齐 4字节对齐 2字节对齐
int a; // 4 4 4
char b; // 1 2(1+1) 2
short c; // 2 2 2
short d; // 2 4(2+2) 2
} My111; typedef struct mystruct2
{ // 1字节对齐 4字节对齐
char a; // 1 4(1+3)
int b; // 4 4
short c;  // 2 4(2+2)
}MyS2; struct mystruct21
{ // 1字节对齐 4字节对齐
char a; // 1 4(1+3)
int b; // 4 4
short c; // 2 4(2+2)
} ;
typedef struct myStruct5
{ // 1字节对齐 4字节对齐
int a; // 4 4
struct mystruct1 s1; // 7 8
double b; // 8 8
int c; // 4 4
}MyS5; struct stu
{ // 1字节对齐 4字节对齐
char sex; // 1 4(1+3)
int length; // 4 4
char name[]; // 10 12(10+2)
};

4.结构体对齐指令

  以#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐参数就是n。

#pragma pack(2)

struct s
{
char c; //2 (1+1)
int b; //4 (4) } ;
#pragma pack()

  取消对齐访问
  __attribute__((packed));
  设置结构体整体对齐访问(不包含元素)
  __attribute__((aligned(n)));

  

struct mystruct11
{ // 1字节对齐 4字节对齐
int a; // 4 4
char b; // 1 2(1+1)
short c; // 2 2
}__attribute__((packed)); typedef struct mystruct111
{ // 1字节对齐 4字节对齐 2字节对齐
int a; // 4 4 4
char b; // 1 2(1+1) 2
short c; // 2 2 2
short d; // 2 4(2+2) 2
}__attribute__((aligned())) My111;

5.offsetof宏与container_of宏

offsetof            在0地址处虚拟出一个结构体,通过元素的地址则为偏移量

container_of     通过元素地址减去偏移量得到结构体地址

typeof()传入变量,返回相应的数据类型。
#include<stdio.h>

struct mystruct
{
char a;
int b;
short c; };
// TYPE是结构体类型,MEMBER是结构体中一个元素的元素名
// 这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int
#define offsetof(TYPE, MEMBER) ((int) &(((TYPE *)0)->MEMBER))//TYPE *为传入值 // ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名
// 这个宏返回的就是指向整个结构体变量的指针,类型是(type *)
//typeof() 是通过变量名 返回数据类型的
#define container_of(ptr, type, member) ({ \
const typeof(((type *))->member) * __mptr = (ptr); \ //定义一个typeof(((type *)0)->member)类型的指针指向 结构体元素地址
(type *)((char *)__mptr - offsetof(type, member)); }) //元素地址-偏移量=结构体首地址
//通过元素地址减去偏移量得到结构体地址
int main()
{
struct mystruct s1;
struct mystruct *Ps;
s1.b=;
int * pb=&s1.b;
Ps=container_of(pb,struct mystruct,b);
printf("container_of宏实例\n");
printf("&s1=%p\n",&s1);
printf("Ps=%p\n",Ps); //int *p=(int *)((char*)&s1+4);
int *p=(int *)((int)&s1+);
printf("*p=%d.\n",*p);
printf("offsetof宏实例\n");
int offsetof_a=offsetof(struct mystruct,a);
int offsetof_b=offsetof(struct mystruct,b);
int offsetof_c=offsetof(struct mystruct,c);
printf("offsetof_a=%d\n",offsetof_a);
printf("offsetof_b=%d\n",offsetof_b);
printf("offsetof_c=%d\n",offsetof_c); return ; }

C语言结构体对齐的更多相关文章

  1. 解析C语言结构体对齐(内存对齐问题)

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  2. 结构体对齐及#pragma详细解释

    在linux下c语言结构体对齐: 1.自然对齐 struct 是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float 等)的变量,也可以是一些复合数据类型(如array.s ...

  3. C语言基础--结构体对齐,位域,联合体

    结构体对齐 1--结构体对齐的原因与意义 许多计算机系统对基本数据类型的可允许地址做出了一些限制,要求某种类型的对象的地址必须是某个值K(通常是2,4,8)的倍数,而这个k则被称为该数据类型的对齐模数 ...

  4. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  5. 4-17疑难点 c语言之【结构体对齐】

    今天学习了结构体这一章节,了解到了结构体在分配内存的时候采取的是对齐的方式 例如: #include<stdio.h> struct test1 { int a; char b; shor ...

  6. [置顶] 什么是C语言结构体字节对齐,为什么要对齐?

    一.概念 对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   ...

  7. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  8. 漫谈C语言结构体struct、公用体union空间占用

    先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; u ...

  9. 浅谈c语言结构体

    对于很多非计算机专业来说,c语言课程基本上指针都不怎么讲,更别说后面的结构体了.这造成很多学生对结构体的不熟悉.这里我就浅谈一下我对结构体的认识. 结构体,就是我们自己定义出一种新的类型,定义好之后, ...

随机推荐

  1. UWP简单示例(一):快速合成音乐MV

    准备 IDE:Visual Studio 2015 为你的项目安装Nuget包 SharpDx.XAudio2 为你的项目安装Nuget包 Win2D.UWP 了解并学习:Win2D官方博客 了解并学 ...

  2. C#中级-常用多线程操作(持续更新)

    一.前言       多线程操作一直是编程的常用操作,掌握好基本的操作可以让程序运行的更加有效.本文不求大而全,只是将我自己工作中常常用到的多线程操作做个分类和总结.平时记性不好的时候还能看看.本文参 ...

  3. 混合框架中Oracle数据库的还原处理操作

    在较早期的随笔<Oracle如何实现创建数据库.备份数据库及数据导出导入的一条龙操作>粗略介绍了Oracle数据库的备份还原操作,本文想从开发框架的基础上介绍Oracle数据库的脚本或者还 ...

  4. [Oracle] Bulk Insert Data

    命名空间:Oracle.DataAccess.Client 组件:Oracle.DataAccess.dll(2.112.1.0) ODP.NET 版本:ODP.NET for .NET Framew ...

  5. Java设计模式——线程安全的单件模式

    单件模式,也称单例模式,用以创建独一无二的.只能有一个实例的对象. 单件模式的类图是所有模式的类图中最简单的--只有一个类.尽管从类设计的视角来看单件模式很简单,但是实现上还是会遇到一些问题,本文着重 ...

  6. (转)ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法

    早上同事用PL/SQL连接虚拟机中的Oracle数据库,发现又报了"ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务"错误,帮其解决后,发现很多人遇到过这样的问 ...

  7. 交易系统使用storm,在消息高可靠情况下,如何避免消息重复

    概要:在使用storm分布式计算框架进行数据处理时,如何保证进入storm的消息的一定会被处理,且不会被重复处理.这个时候仅仅开启storm的ack机制并不能解决上述问题.那么该如何设计出一个好的方案 ...

  8. SQLServer2005+获取表结构信息

    SELECT d.name TableName, a.colorder FieldNo,a.name FieldName, (case when COLUMNPROPERTY( a.id,a.name ...

  9. Vue基本应用

    1.  returnDetail.$mount('#returnDetail');  不用el 直接可以绑定数据到页面的id上 作用区域不能交叠多个vue 实体 否则后面的vue 实体会失效. 2. ...

  10. arcgis api for js入门开发系列二不同地图服务展示(含源代码)

    上一篇介绍了arcgis api离线部署,这篇开始正式介绍arcgis api for js开发:想要学习webgis开发,首先得熟悉了解前端技术,比如界面布局设计的html+css,核心的是java ...