联合体union

本文通过多个示例探讨了C/C++编程中关于union、struct、指针、内存对齐以及大小端存储的问题。涉及内容包括如何利用union访问不同数据类型、内存分配与释放、指针的使用以及大小端系统的判断。同时,文章还提到了空指针、野指针的概念及其重要性,并展示了在实际编程中如何避免这些问题。
摘要由CSDN通过智能技术生成

在这里插入图片描述

union data {
    short st;
    char cs[2];
};

int main() {
    union data x = {};
    x.st = 0x0001;
    if (x.cs[1] == 0) {
    	// 高地址存放高位
        printf("小端\n");
    }
    else {
        printf("大端\n");
    }
    return 0;
}
union data {
    char ch;   // 1 + 3
    // 哑元结构
    union {    // 4
        float f;
        int i;
    };
};


int main() {
    printf("%ld\n", sizeof(union data)); // 4
    return 0;
}
// 此时data1有2个成员,ch和联合体
struct data1 {
    char ch;  // 1 + 3
    union {
    	// 4
        float f;
        int i;
    };
};

// 当类型里嵌套类型的时候,内部类型和外部类型没有关系,只是在设计的时候采用这种方案
// 可以通过外部类型的变量访问内部类型的变量,但是从内存角度而言这个内部变量并不属于外部变量
struct data2 {
	//data2只有1个成员 
    char ch;
    union udata{
        float f;
        int i;
    };
};

int main() {
    printf("%ld\n", sizeof(struct data1)); // 8
    printf("%ld\n", sizeof(struct data2)); // 1
    struct data2 x;
    x.udata = 12; // 这句报错,无法直接访问
    union data2::udata xx; // 通过作用域定义
    return 0;
}
union IPNode {
    unsigned int addr;
    char s3, s2, s1, s0;
};

int main() {
    union IPNode x;
    x.addr = 0x61626364;
    char ch = x.s0;
    printf("%x\n", ch); // 64
    ch = x.s1;
    printf("%x\n", ch); // 64
    ch = x.s2;
    printf("%x\n", ch); // 64
    ch = x.s3;
    printf("%x\n", ch); // 64
    return 0;
}

在这里插入图片描述
注:写成数组的形式,使得内存连续分配,才可得到64、63、62、61

char* getString() {
    char str[] = { "hello" };
    return str;
}

int main() {
    char* str = getString();   // 函数执行完成后,数组str被销毁,str成为失效指针,地址可访问
    printf(str);               // 打印随机值
    strcpy_s(str, 10, "hello"); // 一般而言,str指向空间失效,但是地址有效,应该是可以赋值
    printf(str);               
    free(str);                  // 只有根据malloc的头尾信息进行free
    return 0;
}
char* getString() {
    char* str = "hello"; // 分配至全局区,而不在栈区
    return str;
}

int main() {
    char* str = getString();   // 函数执行完成后,全局区的"hello"不会被销毁
    printf(str);                //打印hello
    strcpy_s(str, 10, "hello"); // 无法赋值,字符串常量可读不可写        
    return 0;
}
int main() {
    int* p = (int*)malloc(sizeof(int));
    *p = 100;
    printf("%d\n", *p); // 正常打印
    free(p);            //free后变成失效指针,将已用标记改成未用标记,但是地址依然有效(野指针的地址无效)
    // 失效指针地址有效,不为0
    if (NULL != p) {
        printf("%d\n", *p);  // 随机值
        *p = 200;            // 正常赋值
        printf("%d\n", *p);  // 正常打印
    }
    free(p);         // 重复free,报错
    return 0;
}
int main() {
    int* p = (int*)malloc(sizeof(int));
    int* s = NULL;
    *p = 100;
    printf("%d\n", *p);
    free(p);                            // 从堆区释放内存,地址还存在,只是存放的数据变成了随机值

    s = (int*)malloc(sizeof(int));      // 这里申请的是和p一样的地址
    *s = 200;        
    printf("%d\n", *p);                 //正常打印
    free(p);                            // 通过p把s释放,因为p和s的地址相同
    free(s);                            // 同一地址重复释放,报错
    return 0;
}

野指针就是不知道指向哪里,或者说不知道指向的内存是否可以使用,一般都是刚刚声明但没有初始化的指针。空指针不是指向常数0,只指向地址0,即NULL,其实换句话说,指针的本质就是地址嘛,空指针就是指针本身的值(地址)为0空指针的作用是防止野指针的出现,因为我们不能知道野指针到底指向哪里,所以我们也无法判断一个指针是否是野指针,这样很危险,但如果养成将指针初始化为空指针的习惯,我们就能判断出这个指针是不是有效的

union B {
    unsigned int a;
    unsigned char b[4];
}g;

int main() {
    g.b[1] = 1;
    printf("%d, %d\n", sizeof(union B), g.a);//4, 256
    return 0;
}

在这里插入图片描述

int get_sys_mode1() {
    union{
        unsigned int a;
        unsigned char b[4];
    }g;
    g.a = 1;
    return g.b[3] == 1;// b[3]是高地址,1是低位
}

int get_sys_mode2() {
    int a = 1;
    int* p = &a;
    return (*(char*)p) == 0;
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值