패딩 구조물을 확장할 때, 왜 여분의 필드를 테일 패딩에 배치할 수 없습니까?
구조를 고려해 보겠습니다.
struct S1 {
int a;
char b;
};
struct S2 {
struct S1 s; /* struct needed to make this compile as C without typedef */
char c;
};
// For the C++ fans
struct S3 : S1 {
char c;
};
S1의 사이즈는 8로 정렬로 인해 예상됩니다.하지만 S2와 S3의 사이즈는 12입니다.즉, 컴파일러는 다음과 같이 구성합니다.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
| a | b | padding | c | padding |
컴파일러는 정렬 제약 조건을 어기지 않고 678의 패딩에 c를 배치할 수 있었습니다.그것을 막는 규칙은 무엇이고, 그 뒤에 있는 이유는 무엇입니까?
단답형(질문의 C++ 부분):Itanium ABI for C++은 역사적인 이유로 POD 유형의 기본 하위 개체의 테일 패딩을 사용하는 것을 금지합니다.C++11에는 이러한 금지가 없습니다.기본 표현을 통해 사소한 형식 복사를 허용하는 관련 규칙 3.9/2는 기본 하위 개체를 명시적으로 제외합니다.
긴 답변:저는 C++11과 C를 한번에 치료해 보겠습니다.
- 의 .
S1
.S1::a
렬해야정합니다합.int
열배S1[N]
는 연적속으성할 개유구다체니됩형 형식으로 됩니다.S1
의 사람들a
구성원이 정렬되어 있어야 합니다. - 에서, 사소한 한 타입의 C++의은 다음과 같습니다.
T
기본 은 기본 하개아것다배수있다처니습리의 할 수 .sizeof(T)
(를 이트즉(객, 포캐수할있스음트를터인바체)에 캐스팅할 수 .unsigned char *
그리고 그 결과를 a의 첫 번째 요소에 대한 포인터로 취급합니다.unsigned char[sizeof(T)]
이 배열의 값이 개체를 결정합니다.).와 같은에, 은 C의 모 개 체 같 종 때 설 같 다 명 합 니 다 이 과 음 에 문 기 든 이 류 는 이 와 은 ▁c 니 ▁since 다 ▁explains 합 ▁in 설 ▁c ▁this 명 , ▁are 의 ▁objects ▁of모S2
C 및 C++의 경우. - C++에 대해 남아 있는 흥미로운 사례는 다음과 같습니다.
- 위 규칙(cf)의 적용을 받지 않는 기본 하위 개체입니다.C++11 3.9/2), 및
- 복사할 수 있는 형식이 아닌 모든 개체.
3.1의 경우 컴파일러가 클래스의 데이터 멤버를 기본 하위 개체로 "압축"하는 일반적인 "기본 레이아웃 최적화"가 있습니다.이는 기본 클래스가 비어 있을 때 가장 두드러지지만(크기 감소율이 %!) 일반적으로 적용됩니다.그러나 위에서 링크한 C++용 Itanium ABI는 각 기본 유형이 POD(및 POD는 사소한 복사 가능 및 표준 레이아웃을 의미)일 때 이러한 테일 패딩 압축을 금지합니다.
3.2의 경우 Itanium ABI와 동일한 부분이 적용되지만, 현재 C++11 표준이 실제로 임의의 복사 불가능한 구성원 개체가 동일한 유형의 전체 개체와 동일한 크기를 가져야 한다고는 생각하지 않습니다.
이전 답변은 참조용으로 보관됩니다.
이 제생에이것 때문이라고 합니다.S1
표준 사양이며, 그래서 어떤 이유에서인지.S1
의 서브오브젝트입니다.S3
손도 대지 않은 채로 있습니다.저는 그것이 기준에 의해 의무화되는지 확실하지 않습니다.
하지만, 우리가 돌아서면,S1
비표준 레이아웃에서 레이아웃 최적화를 관찰합니다.
struct EB { };
struct S1 : EB { // not standard-layout
EB eb;
int a;
char b;
};
struct S3 : S1 {
char c;
};
지금이다sizeof(S1) == sizeof(S3) == 12
내 연단에라이브 데모.
다음은 더 간단한 예입니다.
struct S1 {
private:
int a;
public:
char b;
};
struct S3 : S1 {
char c;
};
를 사용하면 액를통해스세혼합이 됩니다.S1
비표준의(지금sizeof(S1) == sizeof(S3) == 8
.)
업데이트: 정의 요소는 사소한 것뿐만 아니라 표준 레이아웃인 것 같습니다. 즉, 클래스는 POD여야 합니다.기본 레이아웃을 최적화할 수 있는 비POD 표준 레이아웃 클래스는 다음과 같습니다.
struct S1 {
~S1(){}
int a;
char b;
};
struct S3 : S1 {
char c;
};
다시.sizeof(S1) == sizeof(S3) == 8
데모
몇 가지 코드를 고려해 보겠습니다.
struct S1 {
int a;
char b;
};
struct S2 {
S1 s;
char c;
};
만약에 어떤 일이 벌어질지 생각해 봅시다.sizeof(S1) == 8
그리고.sizeof(S2) == 8
.
struct S2 s2;
struct S1 *s1 = &(s2.s);
memset(s1, 0, sizeof(*s1));
이제덮습다니썼을 .S2::c
.
로 인해 다음과 같습니다.S2
또한 9, 10 또는 11의 크기를 가질 수 없습니다.다음 유효한 크기는 12입니다.
를 배치할 수 없는 이유는 과 같습니다.c
▁the▁trailing의 에서.struct S1
원회s
가 컴일러다수가고정니합다다했행음을가파▁place다니▁did▁assume▁▁that▁compiler▁following▁the컴가합파struct S2.c
에 .struct S1.s.
구성원:
struct S1 {
int a;
char b;
};
struct S2 {
struct S1 s; /* struct needed to make this compile as C without typedef */
char c;
};
// ...
struct S1 foo = { 10, 'a' };
struct S2 bar = {{ 20, 'b'}, 'c' };
bar.s = foo; // this will likely corrupt bar.c
memcpy(&bar.s, &foo, sizeof(bar.s)); // this will certainly corrupt bar.c
bar.s.b = 'z'; // this is permited to corrupt bar by C99 6.2.6.1/6
C99/C11 6.2.6.1/6("형식/일반의 표현")은 다음을 의미합니다.
값이 멤버 개체를 포함하여 구조체 또는 유니온 유형의 개체에 저장되는 경우 패딩 바이트에 해당하는 개체 표현의 바이트는 지정되지 않은 값을 사용합니다.
추가 패딩 교육의 배경은 무엇입니까?
프로세서가 정렬에 대해 진지할 경우 예외/신호가 발생하며, 그렇지 않을 경우 정렬 오류로 인해 데이터 액세스가 느려지기 때문에 성능 저하가 발생합니다.
이를 이해하기 위해 데이터 구조 정렬부터 시작하겠습니다.
데이터 구조 정렬은 컴퓨터 메모리에서 데이터를 배열하고 액세스하는 방법입니다.데이터 정렬과 데이터 구조 패딩이라는 두 가지 개별적이지만 관련된 문제로 구성됩니다.최신 컴퓨터가 메모리 주소를 읽거나 쓸 때 워드 크기 청크(예: 32비트 시스템의 경우 4바이트 청크) 이상으로 이 작업을 수행합니다.데이터 정렬은 데이터를 워드 크기의 몇 배에 해당하는 메모리 오프셋에 배치하는 것을 의미하며, CPU가 메모리를 처리하는 방식으로 인해 시스템 성능이 향상됩니다.데이터를 정렬하려면 마지막 데이터 구조의 끝과 다음 데이터 구조 패딩의 시작 사이에 의미 없는 바이트를 삽입해야 할 수 있습니다.
예를 들어 컴퓨터의 워드 크기가 4바이트인 경우(바이트는 대부분의 컴퓨터에서 8비트를 의미하지만 일부 시스템에서는 다를 수 있음) 읽을 데이터는 4의 배수인 메모리 오프셋에 있어야 합니다.그렇지 않은 경우(예: 데이터가 th 바이트가 아닌 th 바이트에서 시작하는 경우), 요청된 데이터를 읽기 전에 컴퓨터가 2개의 4바이트 청크를 읽고 계산을 수행해야 합니다. 그렇지 않으면 정렬 오류가 발생할 수 있습니다.이전 데이터 구조가 13번째 바이트에서 끝나더라도 다음 데이터 구조는 16번째 바이트에서 시작해야 합니다.다음 데이터 구조를 16번째 바이트에 맞추기 위해 두 개의 패딩 바이트가 두 데이터 구조 사이에 삽입됩니다.
패딩 구조물을 확장할 때, 왜 여분의 필드를 테일 패딩에 배치할 수 없습니까?
컴파일러는 정렬 제약 조건을 어기지 않고 678의 패딩에 c를 배치할 수 있었습니다.그것을 막는 규칙은 무엇이고, 그 뒤에 있는 이유는 무엇입니까?
컴파일러는 이 파일을 여기에 배치할 수 있지만 에 대한 메모리 액세스가 잘못되어1 위에서 설명한 대로 성능 저하가 발생합니다.배열 정렬하기
struct __attribute__((__packed__)) mypackedstruct{
char a;
int b;
char c;
};
이 구조는 32비트 시스템에서 컴파일된 크기가 6바이트입니다.
정렬되지 않은 메모리 액세스는 x86 및 amd64와 같은 아키텍처에서 더 느리며 SPARC와 같은 엄격한 정렬 아키텍처에서는 명시적으로 금지됩니다.
1 메모리 액세스는 액세스되는 데이터가 다음과 같을 때 정렬된다고 합니다.n
바이트 길이(여기서 n은 2의 거듭제곱)이며, 데이텀 주소는n
-바이트 정렬.메모리 액세스가 정렬되지 않은 경우 정렬이 잘못되었다고 합니다.
언급URL : https://stackoverflow.com/questions/24110347/when-extending-a-padded-struct-why-cant-extra-fields-be-placed-in-the-tail-pad
'programing' 카테고리의 다른 글
고급 MySql 쿼리: 다른 테이블의 정보로 테이블 업데이트 (0) | 2023.07.30 |
---|---|
MySQL에서 어떤 조합을 선택해야 합니까? (0) | 2023.07.30 |
Dapper.NET을 사용하여 저장 프로시저 호출에서 Oracle OUT 매개 변수 값을 가져옵니다. (0) | 2023.07.25 |
도메인 간 Ajax 요청을 보내는 Phonegap-Javascript (0) | 2023.07.25 |
시간이 너무 오래 걸리는 경우 MySQL 쿼리를 중지하려면 어떻게 해야 합니까? (0) | 2023.07.25 |