# Key Words

## \_\_attribute\_\_ / packed

### 取消对齐的方法

```cpp
#include<stdio.h>
#pragma pack (1)
struct stu{
    char sex;
    int length;
    char name[10];
};
#pragma pack ()

---------------------------------

struct stu{
    char sex;
    int length;
    char name[10];
}__attribute__ ((packed));

int main(){
    struct stu my_stu;
    printf("%x\n%x\n%x\nsize:%d\n", &(my_stu.sex), &(my_stu.length), &(my_stu.name), sizeof(my_stu));
    return 0;
}
```

上面两种定义 stu 的方式都可以屏蔽编译器的自动对齐，输出结果为:

```bash
e714c971
e714c972
e714c976
size:15
```

不对自动对齐限制的情况下输出结果为：

```bash
e2809960
e2809964
e2809968
size:20
```

可以看出编译器遵循的对齐方法： 1. 首先默认4字节对齐，所以`char sex`占`e2809960-e2809963` 2. 对int占4字节`e2809964-e2809967` 3. 对char型数组占10字节`e2809968-e2809971`

最后对整个结构体进行4字节的对齐，故占据4+4+12=20字节

### 探究默认对齐方式

```cpp
#include <stdio.h>  
void main()  
{  
struct A {  
    int a;  
    char b;  
    short c;  
};  

struct B {  
    char b;  
    int a;  
    short c;  
};  

#pragma pack (2) /*指定按2字节对齐*/  
struct C {  
    char b;  
    int a;  
    short c;  
};  
#pragma pack () /*取消指定对齐，恢复缺省对齐*/  



#pragma pack (1) /*指定按1字节对齐*/  
struct D {  
    char b;  
    int a;  
    short c;  
};  
#pragma pack ()/*取消指定对齐，恢复缺省对齐*/  

int s1=sizeof(struct A);  
int s2=sizeof(struct B);  
int s3=sizeof(struct C);  
int s4=sizeof(struct D);  
printf("%d\n",s1);  
printf("%d\n",s2);  
printf("%d\n",s3);  
printf("%d\n",s4);  
}
```

输出结果：

```
8
12
8
7
```

可以发现int的位置影响了整个结构体的大小，这是因为对齐时，长度为n的类型的其实位置要能被n整除，所以对齐时内部结果如下： ![](https://cdn.jsdelivr.net/gh/CookieLau/imghost/img/20200823171259.png)

### 什么时候需要设置对齐？

在设计不同CPU下的通信协议时，或者编写硬件驱动程序时寄存器的结构这两个地方都需要按**一字节对齐**。即使看起来本来就自然对齐的也要使其对齐，以免不同的编译器生成的代码不一样.

### 字节对齐有什么作用？

* 字节对齐的作用不仅是便于cpu快速访问，同时合理的利用字节对齐可以有效地节省存储空间。
* 对于32位机来说，4字节对齐能够使cpu访问速度提高，比如说一个long类型的变量，如果跨越了4字节边界存储，那么cpu要读取两次，这样效率就低了。但是在32位机中使用1字节或者2字节对齐，反而会使变量访问速度降低。所以这要考虑处理器类型，另外还得考虑编译器的类型。在vc中默认是4字节对齐的，GNU gcc 也是默认4字节对齐。  &#x20;

## static

当变量声明为static时，空间将在程序的生命周期内分配。即使多次调用该函数，静态变量的空间也只分配一次，前一次调用中的变量值通过下一次函数调用传递。这对于在C/C ++或需要存储先前函数状态的任何其他应用程序非常有用。 在cpp文件中，全局变量不加static会在汇编的符号表中加上`.global`，全局可访问；加上`static`可以使得该变量只能在本文件中访问，减小访问的范围，在符号表中类似于`.local`，如：

```cpp
    .text
    .const
__ZStL19piecewise_construct:
    .space 1
    .static_data
__ZStL8__ioinit:
    .space    1
    .globl _gg
    .zerofill __DATA,__pu_bss2,_gg,4,2
    .zerofill __DATA,__bss2,__ZL3lqq,4,2
    .text
    .globl _main
```

其中，变量gg是全局变量不带static，变量lqq是static的全局变量。

## Reference

1. [C++那些事](https://light-city.club/sc/)
2. [csdn | C语言字节对齐 **align(),**&#x61;ttribute((aligned (n))),#pragma pack(n)](https://blog.csdn.net/weixin_40204595/article/details/81134560)
3. [C++ static关键字作用](https://blog.csdn.net/ll148305879/article/details/92794360)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://legacy.cookielau.com/archives/1-cpp/7-keywords.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
