IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Linux C/C++字节对齐 -> 正文阅读

[C++知识库]Linux C/C++字节对齐

其实字节对齐是程序员与编译器共同完成的,内存对齐跟编译器、系统、CPU都有关系。

字节对齐的方式

  • 字节对齐的关键字及宏
    #pragma pack()
    alignas()
    attribute
    declspce

pragma

  • 解释
    pragma 指令控制编译器的特定于实现的行为,如禁用编译器警告或更改对齐要求。无法识别的会被忽略。
    这里只对对齐进行说明
    paragma pack 控制字节对齐族有以下格式:
    #pragma pack(m) //设置当前以m字节对齐
    #pragma pack() //设置当前对齐为默认值
    #pragma pack(push) //推入当前对齐的值到内部栈
    #pragma pack(push,m) //推入当前对齐的值到内部栈然后设置以m字节对齐
    #pragma pack(pop) //从内部栈弹出顶条目然后设置(恢复)当前对齐为该值
    下面只是针对#pragma pack(m)测试说明
    注意:在我们的程序中经常看到#pragma pack(m),#pragma pack()成对出现,其实这里的成对出现不像#if与#endif,必须成对,#pragma pack(m)可以单独出现,但这里就会引发一个问题所有直接或间接引用该文件的文件都以指定的m字节对齐,直到遇到下一个#pragma pack
  • 默认的对齐
    默认的结构体对齐方式是以结构体中最大的占用字节的类型对齐,下面结构体中double是8字节对齐,所以
#include <stdio.h>
#include "Fish.h"
struct Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};


int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,23] size:32 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1//这里32= 9 + (3) + 4 + 8 + 1 + (7)       //这里括号内的是空间占位字节,这里将结构体对象的地址以8字节对齐是编译器保证的,比如他的开始地址为8,而T2a是char类型,是1字节对齐,所以其从8开始而8+9不能被四整除,所以加3可以被4整除,这这里9+(3)的位置就是T2b以4字节对齐的位置,而T2c是以8字节对齐的,9 + (3) +  4的位置刚好是T2c对齐地址,所以9+(3)+4+8,而char又是1字节对齐,所以这里9 + (3) + 4 + 8 + 1,而(7)是为了什么呢,其实7主要是考虑了结构体数族,
例如 struct Test2 TB[2]; 那么T[1]的地址也是8字节对齐,所以就有(7)
  • 16字节对齐
#include <stdio.h>
#include "Fish.h"
#pragma pack(16)

struct Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};

#pragma pack()

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}

/demo
[main,26] size:32 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1
这里设置对齐方式为16字节对齐,但是根默认的是一样的

  • 1字节对齐

struct Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};

#pragma pack()

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
./demo 
[main,26] size:22 T2aOf:1 T2bOf:1 T2cOf:1 T2dOf:1
  • pragma pack总结
    从测试可以看出pragma pack() 可以将类型中对齐设置比原来的对齐方式小,但是不能设置比原本的类型对齐大

    alignas()

  • 解释
    指定类型或对象的对齐要求
    alignas 有以下格式:
    alignas( 表达式 ) //表达式 必须是求值为零或合法的对齐或扩展对齐的整型常量表达式
    alignas( 类型标识 ) //等价于 alignas(alignof(类型标识))
    alignas( 包 … ) //等价于对同一说明应用多个 alignas 说明符,逐个对应于形参包的各个成员,形参包可以是类型或非类型形参包
    alignas 说明符可用于:
    类的声明或定义;
    非位域类数据成员的声明;
    变量声明,除了它不能应用于下列内容:
    函数形参;
    catch 子句的异常形参。
    这种声明所声明的对象或类型的对齐要求将等于用于该声明的所有 alignas 说明符中最严格(最大)的非零 表达式,除非这会削弱类型的自然对齐。
    如果某个声明上的最严格(最大)alignas 比当它没有任何 alignas 说明符的情况下本应有的对齐更弱(即弱于其原生对齐,或弱于同一对象或类型的另一声明上的 alignas),那么程序非良构:
    struct alignas(8) S {};
    struct alignas(1) U { S s; }; // 错误:如果没有 alignas(1) 那么 U 的对齐将会是 8
    无效的非零对齐,例如 alignas(3) 非良构。
    同一声明上,比其他 alignas 弱的有效的非零对齐被忽略。
    始终忽略 alignas(0)。
  • 64字节对齐

struct alignas(64) Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};


int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,24] size:64 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1
  • 1字节对齐
#include <stdio.h>
#include "Fish.h"

struct alignas(1) Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};


int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,24] size:32 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1
  • alignas 总结
  • alignas只能在原来结构体对齐的方式上增加对齐字节,但不能在原来基础上减少,恰好根pragma pack相反

attribute

  • 解释
    attribute__是GNU C的一大特性,主要是设置函数、类型(结构体、共用体、基本类型等)及变量属性。
    大致有六个参数值可以被设定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。
    这里只对对齐进行说明
    attribute 控制字节对齐族有以下格式:
    attribute((aligned(m))) //设置当前以m字节对齐
    attribute((packed()))
    下面只是针对__attribute
    ((aligned(m))) 测试说明
  • attribute(aligned(m))
    设置该变量或类型以m字节对齐
#include <stdio.h>
#include "Fish.h"

struct  Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
}__attribute__((aligned(1)));

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,23] size:32 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1

设置的值未能生效

#include <stdio.h>
#include "Fish.h"

struct  Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
}__attribute__((aligned(64)));

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,23] size:64 T2aOf:1 T2bOf:4 T2cOf:8 T2dOf:1

以64位对齐,这里可以看出__attribute__(aligned(m))与alignas一样,可以将其对应的属相对齐在原来对齐基础上增大,但是不能减小

  • attribute((packed(m)))
    使用该属性对struct 或者union 类型进行定义,设定其类型的每一个变量的内存约束。当用在enum 类型 定义时,暗示了应该使用最小完整的类型
#include <stdio.h>
#include "Fish.h"

struct  Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
}__attribute__((packed));

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,23] size:22 T2aOf:1 T2bOf:1 T2cOf:1 T2dOf:1 

对齐方式以1字节对齐了,其实就是前面所说的,以对应结构体属性中的最小的对齐为对齐依据。

paramga pack 与 alignas同时出现

#include <stdio.h>
#include "Fish.h"

#pragma pack(1)

struct alignas(64) Test1
{
    char   T1a[9];
    int    T1b;
    double T1c;
    char   T1d;
};

struct Test2
{
    char   T2a[9];
    int    T2b;
    double T2c;
    char   T2d;
};

#pragma pack()

int main(int argc,char *argv[])
{
    printf("[%s,%d] size:%d T1aOf:%d T1bOf:%d T1cOf:%d T1dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test1),
    alignof(Test1::T1a), alignof(Test1::T1b),
    alignof(Test1::T1c), alignof(Test1::T1d));

    printf("[%s,%d] size:%d T2aOf:%d T2bOf:%d T2cOf:%d T2dOf:%d \n",
    __func__, __LINE__, sizeof(struct Test2),
    alignof(Test2::T2a), alignof(Test2::T2b),
    alignof(Test2::T2c), alignof(Test2::T2d));
}
$ ./demo 
[main,35] size:64 T1aOf:1 T1bOf:1 T1cOf:1 T1dOf:1 
[main,40] size:22 T2aOf:1 T2bOf:1 T2cOf:1 T2dOf:1

declspce

这个没有见过使用的,只是看网上说有,没有深究,有了解的留言分享下,这里先谢谢了

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 00:51:43  更:2022-09-04 00:53:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 11:12:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码