union联合体(c++11非受限联合体、字节对齐)

1.非受限联合体

2.字节对齐

字节对齐原则:

字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

示例:

#include <iostream>
using namespace std;

struct X
{
    short s; /* 2 bytes */          // 首地址宽度要被最宽基本类型大小所整除,所以填充2个字节
             /* 2 padding bytes */
    int   i; /* 4 bytes */              // 偏移量能整除int大小
    char  c; /* 1 byte */            // 结构体总大小要能够整除最宽基本类型,所以填充3个字节
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */          
             /* 1 padding byte */
    short s; /* 2 bytes */          // // 偏移量能整除short大小,所以要对上一个填充一个字节
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */          //// 结构体总大小要能够整除最宽基本类型,所以填充1个字节
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */
int main(int argc, char const *argv[])
{
    cout << "sizeX: "<< sizeX << " sizeY: "<< sizeY << " sizeZ: "<< sizeZ << endl;
    return 0;
}
// sizeX: 12 sizeY: 8 sizeZ: 8

1. 字节对齐不带string类型

字节对齐示例:

#include <iostream>
using namespace std;
// 外来人口信息
struct Foreigner
{
    Foreigner(double s, double ph) : addr(s), phone(ph) {}
    double addr;  // sizeof(double)=8
    double phone;
};

// 登记人口信息
class Person
{
public:
    enum class Category : char {Student, Local, Foreign};
    Person(int num) : number(num), type(Category::Student) {}
    Person(double id) : idNum(id), type(Category::Local) {}
    Person(double addr, double phone) : foreign(addr, phone), type(Category::Foreign) {}
    ~Person() {}

    void print()
    {
        cout << "Person category: " << (int)type << " sizeof:"<< sizeof(type) << endl;
        // cout << "number addr:"<< &number << " idNum addr:"<< &idNum << " foreign addr:" <<&foreign << endl;
        switch (type)
        {
        case Category::Student:
            cout << "Student school number: " << number << " sizeof:" << sizeof(number) << endl;
            break;
        case Category::Local:
            cout << "Local people ID number: " << idNum << " sizeof:" << sizeof(idNum) << endl;
            break;
        case Category::Foreign:
            cout << "Foreigner address: " << foreign.addr
                << ", phone: " << foreign.phone << " sizeof:" << sizeof(foreign) << endl;
            break;
        default:
            break;
        }
    }

private:
    Category type;  // 对齐最长字节8
    union   // 64字节
    {
        int number;
        double idNum;
        Foreigner foreign;  // 元素最宽为8,长度为16
    };
};

union test      // typeof(test) //16
{
    enum class Category : char {Student, Local, Foreign};
    test(int num) : number(num) {}
    ~test() {}
    test(double id) : idNum(id) {}
    test(double addr, double phone) : foreign(addr, phone) {}
    int number;
    double idNum;
    Foreigner foreign;
};

int main()
{
    Person p1(9527);
    Person p2(12.25);
    Person p3(16.5, 1.256);
    p1.print();
    p2.print();
    p3.print();
    cout << "sizeof:"<< sizeof(p3) << endl;     // sizeof:24
    test t(16.5, 1.256);
    cout << "union sizeof:"<< sizeof(t) << endl;    // union sizeof:16
    return 0;
}
// g++ std=c++11 test.cpp -o test
/*
Person category: 0 sizeof:1
Student school number: 9527 sizeof:4
Person category: 1 sizeof:1
Local people ID number: 12.25 sizeof:8
Person category: 2 sizeof:1
Foreigner address: 16.5, phone: 1.256 sizeof:16
sizeof:24
union sizeof:16
*/

带有string类型

How is this possible? String always size 40 and structure sizeof odd reading [duplicate]
有个疑问:Category type; // 偏移了8字节?,string占了32个字节为什么偏移了8个字节?还是string类中最宽基本类型的大小为8字节?

std::string类内部存储一些指针,这些指针在运行时分配给指向保存数据(字符)的动态分配的存储。size()您可以通过调用成员函数(或length())来获取此数据的大小。
对于64位系统来说,指针大小占8个字节,所以对于

#include <iostream>
using namespace std;
// 外来人口信息
struct Foreigner
{
    Foreigner(int s, int ph) : addr(s), phone(ph) {}
    int addr;
    int phone;
};

// 登记人口信息
class Person
{
public:
    enum class Category : char {Student, Local, Foreign};
    Person(int num) : number(num), type(Category::Student) {}
    Person(char id) : idNum(id), type(Category::Local) {}
    Person(int addr, int phone) : foreign(addr, phone), type(Category::Foreign) {}
    ~Person() {}

    void print()
    {
        cout << "Person category: " << (int)type << " sizeof:"<< sizeof(type) << endl;
        // cout << "number addr:"<< &number << " idNum addr:"<< &idNum << " foreign addr:" <<&foreign << endl;
        switch (type)
        {
        case Category::Student:
            cout << "Student school number: " << number << " sizeof:" << sizeof(number) << endl;
            break;
        case Category::Local:
            cout << "Local people ID number: " << idNum << " sizeof:" << sizeof(idNum) << endl;
            break;
        case Category::Foreign:
            cout << "Foreigner address: " << foreign.addr
                << ", phone: " << foreign.phone << " sizeof:" << sizeof(foreign) << endl;
            break;
        default:
            break;
        }
    }

// private:
    Category type;  // 对齐最长字节8
    union   // 64字节
    {
        int number;
        char idNum;
        Foreigner foreign;  // 元素最宽为8,长度为16
    };
};

union test      // typeof(test) //16
{
    enum class Category : char {Student, Local, Foreign};
    test(int num) : number(num) {}
    ~test() {}
    test(char id) : idNum(id) {}
    test(int addr, int phone) : foreign(addr, phone) {}
    int number;
    char idNum;
    Foreigner foreign;
};

struct test2
{
    test2(int num) : number(num) {}
    ~test2() {}
    test2(string id) : idNum(id) {}
    int number;
    string idNum;   // sizeof = 32
};

int main()
{
    Person p1(9527);
    Person p2('a');
    Person p3(16, 1);
    p1.print();
    p2.print();
    p3.print();
    cout << "sizeof:"<< sizeof(p3) << endl;     // sizeof:24
    cout << "   offsetof(number):" << offsetof(Person,  number) << " idNum:"<< offsetof(Person,  idNum) << endl;
    test t(16, 1);
    cout << "union sizeof:"<< sizeof(t) << endl;    // union sizeof:16
    test2 t2("砂隐村村北");
    cout << "struct sizeof:"<< sizeof(t2) << endl;
    cout << "   offsetof(number):" << offsetof(test2,  number) << " idNum:"<< offsetof(test2,  idNum) <<" sizeof(TCHAR)"<< endl;
    return 0;
}
/*
Person category: 0 sizeof:1
Student school number: 9527 sizeof:4
Person category: 1 sizeof:1
Local people ID number: a sizeof:1
Person category: 2 sizeof:1
Foreigner address: 16, phone: 1 sizeof:8
sizeof:12
   offsetof(number):4 idNum:4
union sizeof:8
struct sizeof:40
   offsetof(number):0 idNum:8
*/
posted @ 2022-11-24 16:22  小小灰迪  阅读(257)  评论(0编辑  收藏  举报