共用体——经常被忽略的实用数据类型

共用体定义:

共用体(union)是一种数据格式,它是能够存储不同的数据类型,但只能同时存储其中的一种类型。

特点:

1.成员共用内存

共用体中使用覆盖技术让数据成员之间相互覆盖,以实现不同数据成员共用同一段内存。

union demo
    {
        int a;
        long b;
        double d;
    };
    demo d1;
    cout << "d1   is at: " << &d1 << endl;
    cout << "d1.a is at: " << &d1.a << endl;
    cout << "d1.b is at: " << &d1.b << endl;
    cout << "d1.d is at: " << &d1.d << endl;
2.内存占用与其最大成员相等

由于共用体每次只能存储一个值,为满足共用体成员的内存需要,共用体的内存占用为其最大成员的内存占用。

union demo
    {
        int a;
        char c;
        double d;
    };
    cout << "   int is " << sizeof(int) << "types" << endl;
    cout << "  char is " << sizeof(char) << "types" << endl;
    cout << "double is " << sizeof(double) << "types" << endl;
    cout << " union is " << sizeof(demo) << "types" << endl
3.同时只能有一个成员处于激活态

共用体中起作用的是最后一次存放的成员,在给一个新成员赋值后,旧成员就因被覆盖而失去了作用(这里的新旧是指时间上的)。

union demo
    {
        int a;
        long b;
        char c;
        double d;
    };
    demo d1;
    d1.a = 24;
    d1.d = 33.24;
    d1.b = 1024;
    cout << d1.a << endl << d1.d << endl << d1.b << endl;

运行这段程序的结果表明,输出一个已经失去作用的数据成员是危险的,如果是相同类型并且范围大的覆盖范围小的还好,否则会得到不可预知的结果。从编译器读写数据的角度看,每种数据类型都对应不同的读写格式,假如一个共用体的最大成员占8字节,一个4字节的新成员覆盖了8字节的旧成员,输出旧成员时,由于有一部分已经改变,输出结果当然就不对了。

4.匿名共用体

共用体类型可以没有名称(没有名称的共用体称为匿名共用体),匿名共用体若定义在结构体或类中其共用体成员调用与同样定义在结构体或类中的普通共用体有所不同。

以在类中定义共用体为例


(1)匿名共用体

class Demo
{
public:
    union
    {
        int a;
        long b;
        double d;
    };
};

int main (void)
{
    Demo D1;
    cout << &D1.a << endl;
    cout << &D1.b << endl;
    return 0;
}

(2)普通共用体

class Demo
{
public:
    union demo
    {
        int a;
        long b;
        double d;
    }d1;
};

int main (void)
{
    Demo D1;
    cout << &D1.d1.a << endl;
    cout << &D1.d1.b << endl;
    return 0;
}



运行上面两段程序可以发现,在类(或结构体)中无论是定义普通共用体还是匿名共用体,其公共体成员都使用同一块内存,但两种共用体的成员调用方法却不一样。原因在于,类或结构体将匿名共用体中的共用体成员视为该类或该结构体的两个数据成员,所以不需要中间标识符,但对于有名字的共用体则将其中的共用体成员视为该类或该结构体的同一个数据成员。虽然类或结构体对定义在其中的共用体处理不同,但不影响共用体本身的特性。


应用:

由于共用体的共用内存特性,共用体常用于节省内存。当数据项使用两种或多种格式(但不会同时使用)时,可以用共用体来节省空间。虽然现在的系统内存多达数GB甚至数TB,好像没有必要节省内存,但在嵌入式系统编程中内存十分宝贵。另外,共用体常用于操作系统数据结构或硬件数据结构。


本文为博主原创文章,如需转载请征求博主同意并附上原文链接







### Python中为类的成员变量设置默认值的方式 在Python中,可以通过多种方式为类的成员变量设置默认值。以下是详细的说明: #### 类变量的默认值 当在一个类内部定义变量时,这些变量通常被称为类变量。它们在整个类的作用域内有效,并且可以在不创建任何实例的情况下通过类名访问。如果希望为类变量指定默认值,则可以直接在类体中为其赋初值[^1]。 ```python class Teacher: department = "Computer Science" # 这里设置了部门这个类变量,默认值为"Computer Science" ``` 上述代码展示了如何给`Teacher`类中的`department`类变量赋予初始值 `"Computer Science"`。 #### 实例变量的默认值 对于每个对象独有的状态信息来说,应该使用实例变量而不是类变量。为了初始化实例变量并提供其默认值,在大多数情况下会利用特殊的方法 `__init__()` 来完成这一操作。在这个构造函数里面可以显式地声明各个参数以及相应的默认值[^4]。 ```python class Student: def __init__(self, name="Unknown", age=0): self.name = name # 设置name实例变量,默认值为"Unknown" self.age = age # 设置age实例变量,默认值为0 ``` 这里我们看到两个实例变量被创建出来——一个是学生的姓名(`name`)另一个则是年龄(`age`);而且都给予了各自的缺省数值以便于调用者可以选择忽略传入具体的数据项。 需要注意的是关于可变类型(比如列表或者字典)作为默认参数的情况要特别小心处理因为可能会引发意外的行为[^3]。例如下面的例子展示了一个潜在陷阱: ```python class Course: def __init__(self, students=[]): self.students = students c1 = Course() c2 = Course() c1.students.append('Alice') print(c2.students) # 输出 ['Alice'], 不期望的结果由于共享了相同的students列表 ``` 为了避免这种问题的发生,推荐的做法是以None代替实际的对象来做占位符然后再判断是否需要重新分配一个新的容器结构如下所示: ```python class SafeCourse: def __init__(self, students=None): if students is None: self.students = [] else: self.students = students sc1 = SafeCourse() sc2 = SafeCourse() sc1.students.append('Bob') print(sc2.students) # 正确输出 [], sc1 和 sc2 的 students 列表相互独立 ``` 这样就能够确保每次新建立一个SafeCourse实例的时候都会获得自己单独拥有的空数组而非共用同一份数据副本。 #### 数据类型的多样性支持 另外值得注意的一点就是无论你是打算把什么种类的信息存放到那些成员变量当中去都可以做到这一点得益于Python丰富的内置数据类型体系涵盖了诸如整数、浮点数在内的基本数字类别还有像字符串那样用来表达文本序列的形式再加上集合型别的代表有列表(lists),元组(tuples),字典(dictionaries)[^2]等等几乎满足日常开发所需的一切需求. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值