c语言基础(八)

字节对齐

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

#include<stdio.h>

typedef struct data
{
        int a;               // 4
        char b;             // 1 + 1(填充)
        short c;           // 2    最后整个结构体自身还要对齐
}D;
int main(void)
{
    printf("sizeof(D)=%d.\n",sizeof(D));
    return 0;
}
结果为8byte

注意:

struct data
{
    int a;
    struct data s;   // 1.此时结构体类型(定义)不完整  2.C语言不允许
}s;
int main(void)
{
    unsigned short a = 0x1234;  
    unsigned char * p1 = (unsigned char *)&a, i = 8;
    //*p1 << i,就产生了临时变量,内存中你不知道地址,但是有一个默认类型(int)
    printf("sizeof(*p1 << i) = %d.\n", sizeof(*p1 << i));
    printf("0x%x.\n", *p1 <<= i);    // printf("%d.\n", a *= 2);
    printf("0x%x.\n", *(p1+1));
}
结果如下:sizeof(*p1 << i)=4
        0x0
        0x12
#include<stdio.h>

struct data
{
        int a;                              // 4 + 4(padding)

        struct data *p_next;              //64bit机器指针永远永远占8字节
}S;
int main(void)
{
    printf("sizeof(S)=%d.\n",sizeof(S));
    return 0;
}
结果为16byte

结构体的嵌套

#include<stdio.h>
struct data1
{
        int a;
        short b;
        int c;
        double e;
};//24

typedef struct data
{
        char a;//2
        short b;//2
        int c;//4
        struct data1 s;//24 
        char ch;//8
}S;

int main(void)
{
    printf("sizeof(S)=%d.\n",sizeof(S));
    return 0;
}
结果为40

字段对齐

位字段:专用于结构体,结构体成员的类型必须是:int || unsigned int
有时侯,结构体成员表示的数据很小,就用几个位来表示。
0字段,不可访问,只是占位整个字中剩下的位,全部写0
无名字段,不可访问,只是占位
字(word)=32bit
下一个字段不够在剩余的字存放时,必须另起一个字。字段不能跨字。
超出字段表示的数据范围,结果不可预期
若最后一个字没有填满则也将填满后返回
字段不可取地址

#include <stdio.h>
struct data1
{
    unsigned a : 1;     // 1就是一个bit,范围:0~1
    int : 31;           // 无名字段,不可访问,只是占位
    unsigned b : 2;     // 2就是2个bit,范围:0~3
    unsigned c : 2;   // 28位 
}s1;

int main(void)
{
    printf("szieof(s1) = %d.\n", sizeof(s1));
    return 0;
}
结果为8byte,同时也是2word

特别的是:

struct
{
    int a:1;//此时a只有一位且仅为符号位,取值范围为(-1~0)
};

对齐指令

#pragma pack(n) (1、2、4、8、.....)
#pragma pack()

这两个配合使用,表示一个区间,只有这个区间内的结构体享受这个待遇。
设置 对齐。
如果将n设置为1,就是不对齐
1、充分利用内存空间,牺牲了速度,降低了访问效率。
2、提高效率、性能,牺牲了内存空间。
总结:你指定的对齐方式和结构体自身默认对齐方式,俩者取最小的。

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

#pragma pack(2)
struct data                 // 16
{
    int a;
    char b;
    double c;
}s;

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

检查系统错误的宏

一旦发生了,系统错误就会产生一个错误数字(errno),对应相应的错误字符串。
C标准定义了两个值 EXIT_SUCCESS 和 EXIT_FAILURE,可以作为exit()的参数,来分别指示是否为成功退出。
exit(参数)传递给的是父进程,或者shell终端

#define handle_error(msg)   do{perror(msg); exit(EXIT_FAILURE);}while(0)

Linux内置宏

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

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

#define container_of(ptr, type, member)   ({typeof(((type *)0)->member) *_mptr = ptr;(type *)((char *)_mptr-off_set_of(type, member));})
1、得到结构体成员变量的类型
2、指针赋值(得到真实成员变量的地址值)
3、减去偏移量得到一个数字,该数字和结构体本身首地址在数值上一样
4、最后强制类型转换为结构体指针类型

举个栗子:

#include <stdio.h>

#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));})

struct da
{
    int a;
    short b;    
    int c;
    double e;
};                      // 16
struct data
{
    char a;
    short b;
    int c;              // 8
    struct da s;    // 16
    char ch;
}s = {1, 3, 10, 3.14, 1.41};
//1、不会因为有结构体成员,而影响你的基本类型,决定默认对齐
//2、里面的结构体对齐方式,已经在外面决定了(遍历整个完整结构体)

int main(void)
{
    printf("sizeof(s) = %d.\n", sizeof(s));
    //结构体自身的首地址
    printf("&s = %p.\n", &s);
    struct da *p = container_of(&s.s.b, struct da, b);
    printf("p = %p.\n", p);
    printf("&s.s = %p.\n", &s.s);
    return 0;
}
p->a == (struct data *)0->a;
/*
//让你明白强制转换0地址
struct data *p;     
unsigned long a = 0;        
p = (struct data *)a;  
p->a == (struct data *)0->a;
*/

关于typeof

typeof(),()里面的参数可以是变量名或者表达式。
typeof(int) p

int *p, a;
typeof(p) p_a = &a;//将p_a的类型转换为p的类型,即指针类型
内容概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,重点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理和系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现和不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术和系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计和硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员和技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生和研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法和同步算法的优劣;④为实际OFDM系统的设计和优化提供理论依据和技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试和实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向和技术趋势,如AI增强和毫米波通信,为读者提供了更广阔的视野。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值