CI로 프로그래밍 할 때 GCC를 사용하여 구조체를 패킹하는 것이 매우 중요하다는 것을 알게되었습니다 __attribute__((__packed__))
...]
당신이 언급 했으므로 __attribute__((__packed__))
, 당신의 의도는 struct
( 모든 멤버가 1 바이트 정렬을 갖도록) 내의 모든 패딩을 제거하는 것이라고 가정합니다 .
모든 C 컴파일러에서 작동하는 구조체 패킹에 대한 표준이 없습니까?
... 그리고 대답은 "아니오"입니다. 구조체 (및 스택 또는 힙에 인접한 구조체 배열)와 관련된 패딩 및 데이터 정렬은 중요한 이유로 존재합니다. 많은 컴퓨터에서 정렬되지 않은 메모리 액세스는 잠재적으로 상당한 성능 저하를 초래할 수 있습니다 (일부 최신 하드웨어에서는 줄어듦). 드문 경우이지만 메모리 액세스가 잘못 정렬되면 복구 할 수없는 버스 오류가 발생합니다 (전체 운영 체제가 충돌 할 수도 있음).
C 표준은 이식성에 중점을두기 때문에 구조의 모든 패딩을 제거하고 임의의 필드가 잘못 정렬되도록 표준 방법을 사용하는 것은 의미가 없습니다. 그렇지 않으면 C 코드를 이식 할 수 없게 될 위험이 있습니다.
모든 패딩을 제거하는 방식으로 이러한 데이터를 외부 소스로 출력하는 가장 안전하고 이식성이 좋은 방법은의 원시 메모리 내용을 전송하려고하는 대신 바이트 스트림에서 / 스트림으로 직렬화하는 것 structs
입니다. 또한이 직렬화 컨텍스트 외부에서 프로그램이 성능 저하를 겪는 것을 방지 struct
하고 전체 소프트웨어를 버리고 번쩍이지 않고 자유롭게 새로운 필드를 추가 할 수 있습니다 . 또한 엔디안과 그와 같은 것들을 해결할 수있는 여지가 있습니다.
컴파일러 관련 지시문에 도달하지 않고 모든 패딩을 제거하는 한 가지 방법이 있지만 필드 간의 상대 순서가 중요하지 않은 경우에만 적용 할 수 있습니다. 이런 식으로 주어진 :
struct Foo
{
double x; // assume 8-byte alignment
char y; // assume 1-byte alignment
// 7 bytes of padding for first field
};
... 다음과 같이 이러한 필드를 포함하는 구조의 주소와 관련하여 정렬 된 메모리 액세스를위한 패딩이 필요합니다.
0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
x_______y.......x_______y.......x_______y.......x_______y.......
... 여기서 .
패딩을 나타냅니다. 모든 x
것은 성능 및 때로는 올바른 동작을 위해 8 바이트 경계에 맞춰야합니다.
SoA (어레이의 구조) 표현을 사용하여 패딩을 휴대용 방식으로 제거 할 수 있습니다 (8 개의 Foo
인스턴스 가 필요하다고 가정 합니다).
struct Foos
{
double x[8];
char y[8];
};
우리는 효과적으로 구조를 철거했습니다. 이 경우 메모리 표현은 다음과 같습니다.
0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
x_______x_______x_______x_______x_______x_______x_______x_______
... 이:
01234567
yyyyyyyy
... 더 이상 패딩 오버 헤드가없고 잘못 정렬 된 메모리 액세스가 필요하지 않기 때문에 더 이상 구조 주소의 오프셋으로 이러한 데이터 필드에 액세스하지 않고 대신 효과적으로 배열에 대한 기본 주소의 오프셋으로 액세스합니다.
또한 적은 데이터 소비 (머신의 관련 데이터 소비 속도를 늦추기 위해 더 이상 관련 패딩이 없음)와 컴파일러가 처리를 매우 사소하게 벡터화 할 수있는 가능성으로 인해 순차적 액세스 속도가 빨라집니다. .
단점은 코딩하는 것이 PITA라는 것입니다. 또한 AoS 또는 AoSoA 담당자가 더 잘 수행 할 수있는 필드 간 거리가 넓어 질수록 임의 액세스에있어 잠재적으로 효율성이 떨어집니다. 그러나 그것은 패딩을 제거하고 모든 것을 정렬하지 않고 가능한 한 단단히 포장하는 표준 방법입니다.