구조체의 sizeof가 각 멤버의 sizeof의 합과 같지 않은 이유는 무엇입니까?


698

sizeof연산자가 구조체의 전체 크기보다 구조체에 대해 더 큰 크기를 반환하는 이유는 무엇 입니까?


14
메모리 할당에 대한이 C FAQ를 참조하십시오. c-faq.com/struct/align.esr.html
Richard Chambers

48
일화 : 호스트 프로그램의 구조체 패딩 안에 코드를 넣는 실제 컴퓨터 바이러스가있었습니다.
Elazar

4
@Elazar 인상적입니다! 나는 그런 작은 영역을 무엇이든 사용할 수 있다고 생각하지 않았을 것입니다. 더 자세한 정보를 제공 할 수 있습니까?
OmarL

1
@ Wilson-많은 JMP가 포함되어 있다고 확신합니다.
hoodaticus 2016 년

답변:


649

정렬 제약 조건을 만족시키기 위해 추가 된 패딩 때문입니다. 데이터 구조 정렬 은 프로그램의 성능과 정확성에 모두 영향을줍니다.

  • 잘못 정렬 된 액세스는 어려운 오류 일 수 있습니다 (종종 SIGBUS).
  • 잘못 정렬 된 액세스는 소프트 오류 일 수 있습니다.
    • 적당한 성능 저하를 위해 하드웨어에서 수정되었습니다.
    • 또는 심각한 성능 저하를 위해 소프트웨어의 에뮬레이션으로 수정합니다.
    • 또한 원 자성 및 기타 동시성 보증이 손상되어 미묘한 오류가 발생할 수 있습니다.

다음은 x86 프로세서 (모든 32 비트 및 64 비트 모드 사용)에 대한 일반적인 설정을 사용하는 예입니다.

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

정렬 (기본 유형의 경우 충분한 크기로 정렬) ( Z위 예제의 구조 와 같이)에 따라 멤버를 정렬하여 구조의 크기를 최소화 할 수 있습니다 .

중요 사항 : C 및 C ++ 표준은 모두 구조 정렬이 구현 정의되어 있다고 명시하고 있습니다. 따라서 각 컴파일러는 데이터를 다르게 정렬하여 서로 다른 호환되지 않는 데이터 레이아웃을 만들 수 있습니다. 따라서 다른 컴파일러에서 사용할 라이브러리를 처리 할 때 컴파일러가 데이터를 정렬하는 방법을 이해하는 것이 중요합니다. 일부 컴파일러에는 #pragma구조 정렬 설정을 변경하기위한 명령 줄 설정 및 / 또는 특수 문이 있습니다.


38
여기에 메모하고 싶습니다. 대부분의 프로세서는 정렬되지 않은 메모리 액세스에 대해 당신에게 불이익을 주지만 (많은 사람들이 완전히 허용하지 않는 것을 잊을 수는 없습니다.) 특히 대부분의 MIPS 칩은 정렬되지 않은 액세스에 대해 예외를 발생시킵니다.
Cody Brocious

35
x86 칩은 실제로 벌칙을 받지만 정렬되지 않은 액세스를 허용한다는 점에서 다소 독특합니다. AFAIK 대부분의 칩은 몇 가지가 아닌 예외를 throw합니다. PowerPC가 또 다른 일반적인 예입니다.
다크 시카 리

6
정렬되지 않은 액세스에 대해 pragma를 활성화하면 일반적으로 정렬 오류를 처리하는 프로세서에서 모든 정렬 오류를 수정하는 코드가 생성되어야하기 때문에 코드의 크기가 커집니다. ARM은 또한 정렬 오류를 일으 킵니다.
Mike Dimmick

5
@Dark-완전히 동의합니다. 그러나 대부분의 데스크탑 프로세서는 x86 / x64이므로 대부분의 칩은 데이터 정렬 오류를 발생시키지 않습니다.)
Aaron

27
정렬되지 않은 데이터 액세스는 일반적으로 CISC 아키텍처에서 볼 수있는 기능이며 대부분의 RISC 아키텍처에는이를 포함하지 않습니다 (ARM, MIPS, PowerPC, Cell). 실제로, 대부분의 칩은 데스크탑 프로세서가 아니며 , 많은 칩에 의해 내장 된 규칙이며, 대다수는 RISC 아키텍처입니다.
Lara Dougan

192

패킹 및 바이트 정렬은 FAQ C에 설명 된대로 여기서 :

정렬을위한 것입니다. 대부분의 프로세서는 2 바이트 및 4 바이트 수량 (예 : 정수 및 긴 정수)에 액세스 할 수 없습니다.

이 구조가 있다고 가정하십시오.

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};

이제이 구조를 다음과 같이 메모리에 넣을 수 있다고 생각할 수 있습니다.

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+

그러나 컴파일러가 다음과 같이 정렬하면 프로세서에서 훨씬 더 쉽습니다.

+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+

압축 버전에서 b와 c 필드가 어떻게 둘러싸여 있는지 당신과 내가 조금 어려워하는 것을 주목하십시오. 간단히 말해서 프로세서도 어렵습니다. 따라서 대부분의 컴파일러는 다음과 같이 구조를 채 웁니다 (추가의 보이지 않는 필드가있는 것처럼).

+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+

1
이제 메모리 슬롯 pad1, pad2 및 pad3의 사용은 무엇입니까?
Lakshmi Sreekanth Chitla

7
@YoYoYonnY 불가능합니다. gcc는 실험 옵션을 가지고 있지만 컴파일러는 구조체 멤버를 재정렬 할 수 없습니다
phuclv

@ EmmEff 이것은 잘못되었을 수도 있지만 잘 알지 못합니다 : 왜 배열에 포인터를위한 메모리 슬롯이 없습니까?
Balázs Börcsök

1
@ BalázsBörcsök 이들은 일정한 크기의 배열이므로 해당 요소는 고정 오프셋으로 구조체에 직접 저장됩니다. 컴파일러는 컴파일 타임에이 모든 것을 알고 있으므로 포인터가 암시 적입니다. 예를 들어,이 유형의 struct 변수가 sthen &s.a == &s이고 &s.d == &s + 12(답에 표시된 정렬이 제공됨). 포인터는 배열의 크기가 가변적 인 경우에만 저장 되지만 (예 : 대신에 a선언 된 char a[]경우 char a[3]) 요소를 다른 곳에 저장해야합니다.
kbolino

27

예를 들어 GCC를 사용하여 구조가 특정 크기를 갖도록하려면을 사용하십시오 __attribute__((packed)).

Windows에서는 cl.exe compier를 / Zp 옵션 과 함께 사용할 때 정렬을 1 바이트로 설정할 수 있습니다 .

일반적으로 CPU는 플랫폼 및 컴파일러에 따라 4 (또는 8)의 배수 인 데이터에 액세스하는 것이 더 쉽습니다.

기본적으로 정렬 문제입니다.

변경해야 할 이유가 충분해야합니다.


5
"좋은 이유"예 : 내일 선보일 개념 증명 데모 코드의 복잡한 구조를 위해 32 비트와 64 비트 시스템간에 이진 호환성 (패딩)을 일관되게 유지합니다. 때로는 필요성이 타당성보다 우선해야합니다.
Mr.Ree

2
운영 체제를 언급 한 경우를 제외하고는 모든 것이 정상입니다. 이것은 CPU 속도의 문제이며 OS는 전혀 관여하지 않습니다.
Blaisorblade

3
또 다른 좋은 이유는 네트워크 프로토콜을 구문 분석 할 때와 같이 데이터 스트림을 구조체에 채우는 경우입니다.
ceo

1
@dolmen 방금 OS가 데이터에 액세스하지 않기 때문에 "Operatin 시스템이 데이터에 액세스하는 것이 더 쉽다"고 잘못 지적했습니다.
Blaisorblade

1
@dolmen 사실, ABI (application binary interface)에 대해 이야기해야합니다. 기본 정렬 (소스에서 변경하지 않은 경우 사용)은 ABI에 따라 다르며 많은 OS는 여러 ABI (예 : 32 비트 및 64 비트 또는 다른 OS의 바이너리 또는 여러 가지 컴파일 방법)를 지원합니다. 동일한 OS에 대해 동일한 바이너리). OTOH, 성능 측면에서 편리한 정렬은 CPU에 달려 있습니다 .32 또는 64 비트 모드를 사용하든 메모리는 동일한 방식으로 액세스됩니다 (실제 모드에 대해서는 언급 할 수 없지만 요즘에는 성능과 거의 관련이없는 것으로 보입니다). IIRC Pentium은 8 바이트 정렬을 선호하기 시작했습니다.
Blaisorblade

15

이것은 바이트 정렬 및 패딩으로 인해 구조가 플랫폼의 짝수 바이트 (또는 단어)로 나올 수 있습니다. 예를 들어 Linux의 C에서는 다음 3 가지 구조가 있습니다.

#include "stdio.h"


struct oneInt {
  int x;
};

struct twoInts {
  int x;
  int y;
};

struct someBits {
  int x:2;
  int y:6;
};


int main (int argc, char** argv) {
  printf("oneInt=%zu\n",sizeof(struct oneInt));
  printf("twoInts=%zu\n",sizeof(struct twoInts));
  printf("someBits=%zu\n",sizeof(struct someBits));
  return 0;
}

크기 (바이트)의 멤버는 각각 4 바이트 (32 비트), 8 바이트 (2x 32 비트) 및 1 바이트 (2 + 6 비트)입니다. 위의 프로그램 (gcc를 사용하는 Linux에서)은 4, 8 및 4로 크기를 인쇄합니다. 마지막 구조는 단일 단어 (32 비트 플랫폼에서 4 x 8 비트 바이트)가되도록 채워집니다.

oneInt=4
twoInts=8
someBits=4

4
"gcc를 사용하는 Linux의 C"는 플랫폼을 설명하기에 충분하지 않습니다. 정렬은 주로 CPU 아키텍처에 따라 다릅니다.
고인돌

-@ Kyle Burton. 실례합니다. 왜 "someBits"구조의 크기가 4와 같은지 이해하지 못합니다. 2 개의 정수가 선언 되었기 때문에 (2 * sizeof (int)) = 8 바이트이므로 8 바이트가 필요합니다. 감사합니다
youpilat13

1
안녕 @ youpilat13, :2그리고 :6실제로이 경우 전체 32 비트 정수가 아닌 2 및 6 비트를 지정합니다. someBits.x는 2 비트이므로 00, 01, 10 및 11 (1, 2, 3 및 4)의 4 가지 가능한 값만 저장할 수 있습니다. 이게 말이 되요? 이 기능에 대한 기사는 다음과 같습니다. geeksforgeeks.org/bit-fields-c
Kyle Burton

11

또한보십시오:

Microsoft Visual C의 경우 :

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

GCC는 Microsoft 컴파일러와의 호환성을 주장합니다. :

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

이전 답변 외에도 포장에 관계없이 C ++에는 회원 주문 보증이 없습니다 . 컴파일러는 가상 테이블 포인터와 기본 구조의 멤버를 구조에 추가 할 수 있습니다. 가상 테이블의 존재조차 표준 (가상 메커니즘 구현이 지정되지 않음)에 의해 보장되지 않으므로 그러한 보장이 불가능하다는 결론을 내릴 수 있습니다.

나는 C에서 멤버 순서 보장된다고 확신 하지만 크로스 플랫폼 또는 크로스 컴파일러 프로그램을 작성할 때 그것을 믿을 수는 없습니다.


4
"회원 주문이 C로 과장된 것 같습니다." C99는 "구조 객체 내에서 비트 필드가 아닌 멤버와 비트 필드가있는 유닛은 선언 된 순서대로 주소가 증가합니다."라고 말합니다. 보다
나은


8

구조의 크기는 소위 패킹 (packing)으로 인해 부분의 합보다 큽니다. 특정 프로세서는 선호하는 데이터 크기를 가지고 있습니다. 32 비트 (4 바이트) 인 경우 최신 프로세서의 기본 크기입니다. 데이터가 이런 종류의 경계에있을 때 메모리에 액세스하는 것이 해당 크기 경계를 넘는 것보다 효율적입니다.

예를 들어. 간단한 구조를 고려하십시오.

struct myStruct
{
   int a;
   char b;
   int c;
} data;

머신이 32 비트 머신이고 데이터가 32 비트 경계에 정렬되면 즉각적인 문제가 발생합니다 (구조 정렬이 없다고 가정). 이 예에서는 구조 데이터가 주소 1024에서 시작한다고 가정합니다 (0x400-가장 낮은 2 비트가 0이므로 데이터가 32 비트 경계에 정렬 됨). data.a에 대한 액세스는 경계-0x400에서 시작하기 때문에 제대로 작동합니다. data.b에 대한 액세스는 또 다른 32 비트 경계인 주소 0x404에 있기 때문에 제대로 작동합니다. 그러나 정렬되지 않은 구조는 data.c를 주소 0x405에 넣습니다. data.c의 4 바이트는 0x405, 0x406, 0x407, 0x408에 있습니다. 32 비트 시스템에서 시스템은 한 메모리주기 동안 data.c를 읽지 만 4 바이트 중 3 바이트 만 가져옵니다 (4 번째 바이트는 다음 경계에 있음). 따라서 시스템은 4 번째 바이트를 얻기 위해 두 번째 메모리 액세스를 수행해야합니다.

이제 data.c를 주소 0x405에 넣는 대신 컴파일러가 구조를 3 바이트로 채우고 data.c를 주소 0x408에 놓으면 시스템은 데이터를 읽는 데 1 주기만 필요하므로 해당 데이터 요소에 대한 액세스 시간이 단축됩니다. 50 %까지 패딩은 처리 효율성을 위해 메모리 효율성을 바꿉니다. 컴퓨터가 엄청난 양의 메모리 (수 기가 바이트)를 가질 수 있다고 가정하면 컴파일러는 스왑 (크기 초과 속도)이 합리적이라고 생각합니다.

불행히도 네트워크를 통해 구조를 보내거나 이진 데이터를 이진 파일에 쓰려고 할 때이 문제가 발생합니다. 구조 또는 클래스의 요소 사이에 삽입 된 패딩은 파일 또는 네트워크로 전송 된 데이터를 방해 할 수 있습니다. 이식 가능한 코드 (여러 개의 다른 컴파일러로 이동하는 코드)를 작성하려면 적절한 "패킹"을 보장하기 위해 구조의 각 요소에 개별적으로 액세스해야합니다.

반면에, 컴파일러마다 데이터 구조 패킹을 관리하는 능력이 다릅니다. 예를 들어 Visual C / C ++에서 컴파일러는 #pragma pack 명령을 지원합니다. 이를 통해 데이터 패킹 및 정렬을 조정할 수 있습니다.

예를 들면 다음과 같습니다.

#pragma pack 1
struct MyStruct
{
    int a;
    char b;
    int c;
    short d;
} myData;

I = sizeof(myData);

이제는 길이가 11이되어야합니다. pragma가 없으면 컴파일러의 기본 패킹에 따라 11에서 14까지 (그리고 일부 시스템에서는 32까지) 될 수 있습니다.


이것은 구조 패딩의 결과에 대해 논의하지만 질문에 대답하지는 않습니다.
키이스 톰슨

" ... 패킹 (packing) " 때문에 ...- "패딩 (padding)"을 의미한다고 생각합니다. " 32 비트 (4 바이트) 인 경우 대부분의 최신 프로세서가 선호하는 크기 "-이것은 약간 단순화 된 것입니다. 8, 16, 32 및 64 비트 크기가 지원되며, 각 크기마다 고유 한 정렬이 있으며, 아직 답변에 아직 포함되지 않은 새로운 정보가 있는지 확실하지 않습니다.
Keith Thompson

1
패킹 할 때 컴파일러가 데이터를 구조로 압축하는 방법을 의미했습니다 (작은 항목을 패딩하여 그렇게 할 수 있지만 패딩 할 필요는 없지만 항상 패킹합니다). 크기와 관련하여 시스템이 데이터 액세스를 지원하지 않는 시스템 아키텍처에 대해 이야기했습니다 (기본 버스 아키텍처와는 다른 방식). 마지막 의견에 관해서는 주요 프로그래밍 문제 인 트레이드 오프 (속도 대 크기)의 한 측면에 대해 간단하고 확장 된 설명을주었습니다. 또한 문제를 해결하는 방법에 대해서도 설명합니다.
sid1138

이 문맥에서 "포장"은 일반적으로와 같이 구성원을 기본값보다 더 엄격하게 할당하는 것을 말합니다 #pragma pack. 멤버가 기본 정렬에 할당되면 일반적으로 구조가 패킹 되지 않았다고 말합니다 .
키스 톰슨

포장은 일종의 과부하입니다. 구조 요소를 메모리에 넣는 방법을 의미합니다. 상자에 물건을 넣는 의미와 비슷합니다 (이동을위한 포장). 또한 패딩없이 요소를 메모리에 넣는 것을 의미합니다 ( "밀폐 포장"을위한 짧은 손 정렬). 그런 다음 #pragma pack 명령에 단어의 명령 버전이 있습니다.
sid1138

5

구조체의 정렬을 암시 적으로 또는 명시 적으로 설정 한 경우 그렇게 할 수 있습니다. 4로 정렬 된 구조체는 멤버의 크기가 4 바이트의 배수가 아닌 경우에도 항상 4 바이트의 배수입니다.

또한 라이브러리는 32 비트 정수로 x86에서 컴파일 될 수 있으며 64 비트 프로세스에서 해당 구성 요소를 비교하면 수동으로 수행하는 경우 다른 결과를 얻을 수 있습니다.


5

C99 N1256 표준 초안

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 연산자의 크기 :

3 구조 또는 공용체 유형을 갖는 피연산자에 적용되면 결과는 내부 및 후행 패딩을 포함하여 이러한 오브젝트의 총 바이트 수입니다.

6.7.2.1 구조 및 공용체 지정자 :

13 ... 구조 객체 내에 이름없는 패딩이있을 수 있지만 시작 부분에는 없습니다.

과:

15 구조체 나 공용체 끝에 이름없는 패딩이있을 수 있습니다.

새로운 C99 Flexible Array 멤버 기능 ( struct S {int is[];};)도 패딩에 영향을 줄 수 있습니다.

특별한 경우, 하나 이상의 명명 된 멤버가있는 구조의 마지막 요소는 불완전한 배열 유형을 가질 수 있습니다. 이것을 유연한 배열 구성원이라고합니다. 대부분의 경우 가변 배열 멤버는 무시됩니다. 특히, 구조의 크기는가요 성 어레이 부재가 생략되는 것보다 더 많은 후미 패딩을 가질 수 있다는 것을 제외하고는가요 성 어레이 부재가 생략 된 것과 같다.

부속서 J 이식성 문제는 다음을 반복한다.

다음은 지정되지 않았습니다 : ...

  • 구조체 또는 공용체에 값을 저장할 때 패딩 바이트의 값 (6.2.6.1)

C ++ 11 N3337 표준 초안

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 크기 :

2 클래스에 적용하면 결과는 해당 유형의 객체를 배열에 배치하는 데 필요한 패딩을 포함하여 해당 클래스의 객체에있는 바이트 수입니다.

9.2 반원 :

reinterpret_cast를 사용하여 적절히 변환 된 표준 레이아웃 구조체 객체에 대한 포인터는 초기 멤버 (또는 해당 멤버가 비트 필드 인 경우 해당 필드가있는 단위)를 가리키고 그 반대도 마찬가지입니다. [참고 : 표준 레이아웃 구조체 안에는 이름이없는 패딩이있을 수 있지만, 적절한 정렬을 위해 필요에 따라 시작 부분에는 없습니다. — 끝 참고]

나는 메모를 이해하기에 충분한 C ++ 만 알고 있습니다 :-)


4

다른 답변 외에도 구조체는 가상 함수를 가질 수 있지만 일반적으로 구조체의 크기는 vtbl의 공간을 포함합니다.


8
좀 빠지는. 일반적인 구현에서 struct에 추가되는 것은 vtable pointer 입니다.
Don Wakefield

3

C 언어는 메모리에서 구조적 요소의 위치에 대해 컴파일러에게 약간의 자유를 남깁니다.

  • 메모리 구멍은 두 구성 요소 사이와 마지막 구성 요소 뒤에 나타날 수 있습니다. 대상 컴퓨터의 특정 유형의 개체는 주소 지정의 경계에 의해 제한 될 수 있기 때문입니다
  • "메모리 홀"크기는 sizeof 연산자의 결과에 포함됩니다. sizeof에는 C / C ++에서 사용할 수있는 유연한 배열의 크기 만 포함되지 않습니다.
  • 언어의 일부 구현을 통해 pragma 및 컴파일러 옵션을 통해 구조의 메모리 레이아웃을 제어 할 수 있습니다

C 언어는 프로그래머가 구조의 요소 레이아웃을 확실하게 보장합니다.

  • 메모리 주소를 증가시키는 일련의 구성 요소를 할당하는 데 필요한 컴파일러
  • 첫 번째 구성 요소의 주소는 구조의 시작 주소와 일치합니다
  • 명명되지 않은 비트 필드는 인접한 요소의 필요한 주소 정렬에 대한 구조에 포함될 수 있습니다

요소 정렬과 관련된 문제 :

  • 다른 컴퓨터는 다른 방법으로 물체의 가장자리를 따라
  • 비트 필드의 너비에 대한 다른 제한
  • 컴퓨터는 바이트를 단어로 저장하는 방법이 다릅니다 (Intel 80x86 및 Motorola 68000)

정렬 작동 방식 :

  • 구조가 차지하는 부피는 그러한 구조의 어레이의 정렬 된 단일 요소의 크기로서 계산된다. 다음 구조의 첫 번째 요소가 정렬 요구 사항을 위반하지 않도록 구조를 종료해야합니다.

ps 더 자세한 정보는 여기에 있습니다 : "Samuel P.Harbison, Guy L.Steele CA Reference, (5.6.2-5.6.7)"


2

속도와 캐시를 고려할 때 피연산자는 원래 크기로 정렬 된 주소에서 읽어야합니다. 이를 위해 컴파일러는 구조 멤버를 패딩하여 다음 멤버 또는 다음 구조체가 정렬되도록합니다.

struct pixel {
    unsigned char red;   // 0
    unsigned char green; // 1
    unsigned int alpha;  // 4 (gotta skip to an aligned offset)
    unsigned char blue;  // 8 (then skip 9 10 11)
};

// next offset: 12

x86 아키텍처는 항상 잘못 정렬 된 주소를 가져올 수있었습니다. 그러나 속도가 느리고 정렬 불량이 두 개의 다른 캐시 라인과 겹치면 정렬 된 액세스가 하나만 제거 할 때 두 개의 캐시 라인을 제거합니다.

일부 아키텍처는 실제로 잘못 정렬 된 읽기 및 쓰기와 ARM 아키텍처의 초기 버전 (오늘날의 모든 모바일 CPU로 발전한 아키텍처)을 포착해야합니다. (그들은 하위 비트를 무시했습니다.)

마지막으로 캐시 라인은 임의로 커질 수 있으며 컴파일러는이를 추측하거나 공간 대 속도를 절충하지 않습니다. 대신, 정렬 결정은 ABI의 일부이며 결국 캐시 라인을 균일하게 채울 최소 정렬을 나타냅니다.

TL; DR : 정렬이 중요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.