课堂总结5

字节对齐详细讲解
1、我们的结构体变量本身就是在4字节对齐的位置,编译器帮我们做的事。
2、第一个成员,就从结构体开始的地址处,存放。这个元素,具体占多少字节,由紧挨着下个元素决定。
3、整个成员变量自身都对齐 了,还没有结束。
4、整个结构体还要是默认字节对齐的最小整数倍。
结构体默认的字节对齐:成员变量最大的那个类型所占字节
64位机下在设置对齐时会将结构体最大的元素与8字节比较,取其小

例如在如下例子中
最大的成员是a(4字节)<8字节
所以以4字节对齐

typedef struct data
{
        int a;              // 4
        char b;             // 1 + 1(填充)
        short c;          // 2    最后整个结构体自身还要对齐
//      double d;
}D;//8字节

下例中最大成员是b(8字节)
根据上面的说法 以8字节对齐

struct data1
{
        int a;//4+4(填充)
        double b;//8
}d;//16字节

字节对齐命令
#pragma pack(n) (1、2、4、8、…..)
……
#pragma pack()
这两个配合使用,表示一个区间,只有这个区间内的结构体享受这个待遇。
设置 对齐。
设置为1,就是不对齐
1、充分利用内存空间,牺牲了速度,降低了访问效率。
2、提高效率、性能,牺牲了内存空间。
总结:你指定的对齐方式和结构体自身默认对齐方式,俩者取最小的。
用法举例:
下例的意思是以2字节对齐
所以是s1结果是14
s1是2

#pragma pack(2)
struct data                 
{
        int a;//2*2字节
        char b;//1+1(填充)
        double c;//2*4字节
}s;

struct data1
{
        char ch;
}s1;
#pragma pack()

位字段
位字段:专用于结构体,结构体成员的类型必须是:int || unsigned int
有时侯,结构体成员表示的数据很小,就用几个位来表示。
下例1
a占32位中的1bit
b占2bit
c占2bit
后面全部填充

struct data  //4
{
        unsigned a : 1;  // 1就是一个bit,范围:0~1
        unsigned b : 2;  // 2就是er个bit,范围:0~3
        unsigned c : 2; // 28位 
}s, *p = &s;

例子2

struct data2    //12
{
        unsigned a : 1;     // 1就是一个bit,范围:0~1
        int : 0;                    // 0字段,不可访问,只是占位  整个字剩下的位,全部写0
        unsigned b : 30;    // 2就是er个bit,范围:0~3
        int : 0;
        unsigned c : 2;   // 28位 
}s2;

例子3

struct data3   //8
{
        int a : 2;//先占2个bit 后面的30个全部填充
        int b : 32;
}s3;

linux内核里的两个宏:在驱动应用中很广泛。
1, off_set_of(type, member)计算结构体内元素的偏移量
2, containe_of(ptr, type, member),ptr是结构体里成员的指针,通过调用这个宏计算出结构体的首地址.包含两句代码(表达式),必须要加{}.
这两个宏:内核双链表。

#define off_set_of(type, member) ((long)&(((type *)0)->member))

#define container_of(ptr, type, member) ({typeof(((type )0)>member) *_mptr = ptr;(type )((char )_mptr-off_set_of(type, member));})

分析:1、(type *)0指向结构体零地址 \
2、((type *)0)->member得到了结构体某个成元变量名 \
3、给这成员变量名,取地址(相对于零地址),此时&(((type *)0)->member)表示是指针类型 \
4、强制类型转换成long。

struct da
{
        int a;
        short b;
        int c;
        double e;
};                      // 16
struct data
{
        char a;      //2
        short b;     //2
        int c;      // 4
//      float d;    // 8
//  double e;       // 8
        struct da s;    // 16
        char ch;
}s = {1, 3, 10, 3.14, 1.41};
int main(void)
{
    int off = off_set_of(struct data, c);
    printf("off = %d.\n", off);     // off 4
    ff = off_set_of(struct data, d);
    printf("off = %d.\n", off);         // off 8
    off = off_set_of(struct data, e);
    printf("off = %d.\n", off);         // off 16
}
struct data *p = container_of(p_e, struct data, e);

得到成员e的结构体首地址

枚举类型以及简单密码锁的编写

typedef enum STATE
{
        STATE1,  //0
        STATE2,  //1
        STATE3,  //2.......
        STATE4,
        STATE5,
        STATE6,
        STATE7,
}S;

如果

typedef enum  fangxiang                         // 标识符
{
        EAST,
        WEST = 99,
        SAUTH,
        NORTH = 100,
        xq,
}E;

在这里SAUTH==100;
NORTH==100;

简单密码锁实例代码

int main(void)
{
        int num = 0;
        //1、密码锁初始状态
        S current_state = STATE1;
        // 输入密码,进行解锁
        printf("输入一个密码数字:");
        while (1)
        {
                scanf("%d", &num);
                printf("num = %d.\n", num);
                //解锁子开始
                switch (current_state)
                {
                        case STATE1:
                        if (num == 9)
                                        current_state = STATE2; // 用户每输对一次,进入下一状态
                        else
                                        current_state = STATE1;
                        break;
                        case STATE2:
                        if (num == 5)
                                        current_state = STATE3;  // 用户每输对一次,进入下一状态
                        else
                                        current_state = STATE1;
                        break;
                        case STATE3:
                        if (num == 2)
                                        current_state = STATE4; // 用户每输对一次,进入下一状态
                        else
                                        current_state = STATE1;
                        break;
                        case STATE4:
                        if (num == 7)
                                        current_state = STATE5;  // 用户每输对一次,进入下一状态
                        else
                                        current_state = STATE1;
                        break;
                        default:
                        current_state = STATE1;
                        break;      
                }
                if (current_state == STATE5)
                {
                        printf("开了锁,请进!.\n");
                        //break
                        return 0;
                }
                if (current_state == STATE1)
                        printf("初始状态.\n");
        }
    return 0;
}

网络结构体ipv4

在网络中传送过去的IP/PORT都是网络字节序,大端模式:低位(字节)要放到高地址

struct in_addr
  {
    in_addr_t s_addr;
  };

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);               /* AF_INET IPv4 Internet protocols  指定网络地址类型*/ 
    in_port_t sin_port;                         /* Port number. 端口号 16位无符号short */
    struct in_addr sin_addr;            /* Internet address.  具体的网址32位无符号int*/

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

头文件:

#include <stdio.h>
#include <features.h>
#include <stdint.h>
#include <sys/socket.h>
#include <bits/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

类型定义/宏定义

typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
#define PORT 0x1234
#define ADDR "192.168.1.22"

给每个成员赋值

void set_net_struct(struct sockaddr_in *p)
{
        p->sin_family = AF_INET;
        p->sin_port = htons(PORT);
        p->sin_addr.s_addr = inet_addr(ADDR);
}

柔性数组
柔性数组:是在结构体里,有一个数组,必须是结构体最后的一个元素,而且由特定形式[]或[0];
整体的结构体至少有两个成员变量。

typedef struct
{
        int len;
        int arr[];
}S;
//生成柔性数组
void create_soft_arr(int len)
{
        S *p = (S *)malloc(sizeof(S) + sizeof(int)*len);
        //让a成员控制我数组个数
        p->len = len;
        int i = 0;
        for (i=0; i<len; i++)
        {
                if (i <= 1)
                        p->arr[i] = 1;
                else if (i >= 2)
                        p->arr[i] = p->arr[i-1] + p->arr[i-2];
        }
        //看一下 用func
        free(p);
}

结构体函数

typedef int (*p_func)(int a, int b);

int add(int a, int b)
{
        return a + b;
}
int mul_a_b(int a, int b)
{
        int sum = 1;
        while (b--)
        sum *= a;
        return sum;
}
//结构体各成员默认是public
//class在C++里,是一个类,所有成员和方法(函数)是si(private)有的,只能在类里进行访问
//struct里面不能包含函数,但是可以包含函数指针
struct data
{
        int a;
        int b;
        p_func p;
        //不能有函数
//      int add(int a, int b);
}s;
//填充结构体
void set_func(struct data *p)
{
        p->a = 2;
        p->b = 3;
//      p->p = add;
        p->p = mul_a_b;
}
//业务函数
int cnt_func(struct data *p_str)
{
        return p_str->p(p_str->a, p_str->b);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值