[C 언어] 구조체의 메모리 정렬

1. 구조 메모리 정렬 규칙


1. 첫 번째 멤버는 구조체 변수의 오프셋이 0인 주소에 있습니다.
2. 다른 멤버 변수는 특정 숫자(정렬 번호)의 정수배인 주소(오프셋)에 정렬되어야 합니다. gcc 컴파일러 기본 정렬 번호가 없습니다. 멤버 크기는 정렬 번호입니다
. 정렬 번호 = 컴파일러의 기본 정렬 번호(VS 기본값은 8)와 멤버 크기 사이의 작은 값입니다. 3.
구조체의 전체 크기는 최대 정렬 수(각 멤버 변수는 정렬 수의 정수 배수를 가짐)
4. 구조가 중첩된 경우 중첩된 구조는 자체 최대 정렬 수의 정수 배수로 정렬되며 구조의 전체 크기는 최대입니다. 모든 정렬 번호(중첩 구조 포함) 본체 정렬 번호의 정수배)


다음 코드를 참조하세요.

struct S1//结构体变量
{
    
    
	char c1;//1 c1 第一个成员
	int a;//4   4<8 对齐数为4  此时4为该结构体的最大对齐数
	char c2;//1 对齐数为1
};
struct S2
{
    
    
	char c1;//1
	char c2;//1
	int a;//4
};
#include<stdio.h>
int main()
{
    
    
	struct S1 s1 = {
    
     0 };
	printf("%d\n", sizeof(s1));
	struct S2 s2 = {
    
     0 };
	printf("%d\n", sizeof(s2));
	return 0;
}

작업 결과:

12
8

설명(S1을 예로 들어):

  • 1. 첫 번째 멤버는 구조 변수의 주소 오프셋 0에 있습니다. 코드에서 c1이 첫 번째 멤버이고 c1이 1바이트를 차지하므로 아래 그림의 파란색 부분에 c1이 저장됩니다.

  • 2. 다른 멤버 변수는 특정 숫자(alignment number)의 정수배인 주소(offset)에 정렬되어야 합니다.gcc 컴파일러에는 기본 정렬 번호가 없으며 멤버 크기는 정렬 번호입니다.
    정렬 번호 = 컴파일러의 기본 정렬 번호(VS 기본값은 8)와 멤버 크기 사이의 더 작은 값입니다.
    저는 VS를 사용하고 있으므로 기본 정렬 번호는 8입니다. 두 번째 멤버 c2의 크기는 4, 4<8이므로 c2의 정렬 번호는 4이므로 c2는 오프셋 4 이후에 저장된 숫자가 없기 때문에 오프셋 4의 배수인 숫자를 저장하기 시작합니다. c2는 오프셋 4부터 저장되기 시작하고 c2는 4바이트를 차지하므로 아래 그림의 녹색 부분에 c2가 저장됩니다.

  • 같은 방법으로 아래 그림의 주황색 부분에 c3이 저장됩니다.

  • 3. 구조체의 전체 크기는 최대 정렬 번호의 정수배입니다(각 멤버 변수에는 정렬 번호가 있습니다). 규칙에 따라 c1 c2 c3을 저장한 후 총 1+4+1=6바이트를 차지해야 하는데 결과는 12입니다. 처음 세 가지 정렬 규칙에 따르면 흰색 부분은 비어 있어야 하기 때문에 이 정렬 규칙에 따르면 c2의 크기가 가장 큰 4이므로 S1의 최대 정렬 개수는 4입니다. 규칙, add 위쪽 공백 부분은 9이고 가장 가까운 4의 배수는 12이므로 공백 부분 3개, 즉 노란색 부분을 더 추가해야 합니다.

  • 여기에 이미지 설명을 삽입하세요.

  • 요약하면 구조체 S1의 크기는 12입니다.

  • 계산 결과를 통해 c1과 a의 위치만 변경하면 구조의 크기가 12에서 8로 변경되므로 공간이 작은 멤버들을 최대한 함께 유지해야 한다는 것을 알았습니다.


  • 4. 구조가 중첩되고 중첩된 구조가 자체 최대 정렬 번호의 정수 배수로 정렬되는 경우 구조의 전체 크기는 모든 최대 정렬 번호(중첩 구조의 정렬 번호 포함)의 정수입니다. 시간 코드
    참조 :
struct S3
{
    
    
	double d;//8
	char c;//1
	int i;//4
};
struct S4
{
    
    
	char c1;//1
	struct S3 s3;//16 最大对齐数为8 从偏移量为8的时候开始
	double d;//8
};
#include<stdio.h>
int main()
{
    
    
	struct S3 s3 = {
    
     0 };
	printf("%d\n", sizeof(s3));
	struct S4 s4 = {
    
     0 };
	printf("%d\n", sizeof(s4));
	return 0;
}

작업 결과:

16
32

설명하다:

  • 정렬 규칙에 따르면 S3의 크기는 16임을 알 수 있습니다.
  • S4 크기를 계산하면 16>8이므로 정렬 개수는 8입니다.
  • S4의 크기는 32와 비슷하게 계산할 수 있습니다.

2. 메모리 정렬은 왜 존재하는가?

  • 1. 플랫폼 이유(이식 이유): 모든 하드웨어 플랫폼이 모든 주소의 데이터에 액세스할 수 있는 것은 아닙니다. 일부 하드웨어 플랫폼은 특정 주소에서 특정 유형의 데이터만 얻을 수 있습니다. 그렇지 않으면 하드웨어 예외 2가 발생합니다. 성능 이유: 데이터
    구조 (특히 스택)은 가능할 때마다 자연스러운 경계에 정렬되어야 합니다. 그 이유는 정렬되지 않은 메모리에 액세스하려면 프로세서가 두 번의 메모리 액세스를 수행해야 하지만 정렬된 메모리 액세스에는 한 번의 액세스만 필요하기 때문입니다. 일반적으로
    구조의 메모리 정렬은 공간을 시간과 교환하는 것입니다.
  • 그렇다면 구조를 설계할 때 공간을 절약하면서 정렬을 달성하는 방법은 무엇입니까?
    1. 공간이 작은 멤버들은 최대한 모아야 한다.
    2. 일반적으로 2의 거듭제곱인 기본 정렬 번호 #pragma를 수정한다.

Supongo que te gusta

Origin blog.csdn.net/m0_74102736/article/details/130451808
Recomendado
Clasificación